Browse Source

Improved game organization

Arnaud Vergnet 4 years ago
parent
commit
c75a7dc8fc

+ 23
- 78
screens/Tetris/GameLogic.js View File

@@ -1,6 +1,6 @@
1 1
 // @flow
2 2
 
3
-import Tetromino from "./Tetromino";
3
+import Piece from "./Piece";
4 4
 
5 5
 export default class GameLogic {
6 6
 
@@ -28,7 +28,7 @@ export default class GameLogic {
28 28
     score: number;
29 29
     level: number;
30 30
 
31
-    currentObject: Tetromino;
31
+    currentObject: Piece;
32 32
 
33 33
     gameTick: number;
34 34
     gameTickInterval: IntervalID;
@@ -39,7 +39,7 @@ export default class GameLogic {
39 39
     autoRepeatActivationDelay: number;
40 40
     autoRepeatDelay: number;
41 41
 
42
-    nextPieces: Array<Tetromino>;
42
+    nextPieces: Array<Piece>;
43 43
     nextPiecesCount: number;
44 44
 
45 45
     onTick: Function;
@@ -62,12 +62,11 @@ export default class GameLogic {
62 62
         this.nextPiecesCount = 3;
63 63
     }
64 64
 
65
-    getNextPieces() {
65
+    getNextPiecesPreviews() {
66 66
         let finalArray = [];
67 67
         for (let i = 0; i < this.nextPieces.length; i++) {
68 68
             finalArray.push(this.getEmptyGrid(4, 4));
69
-            let coord = this.nextPieces[i].getCellsCoordinates(false);
70
-            this.tetrominoToGrid(this.nextPieces[i], coord, finalArray[i]);
69
+            this.nextPieces[i].toGrid(finalArray[i], true);
71 70
         }
72 71
 
73 72
         return finalArray;
@@ -113,14 +112,8 @@ export default class GameLogic {
113 112
     }
114 113
 
115 114
     getFinalGrid() {
116
-        let coord = this.currentObject.getCellsCoordinates(true);
117 115
         let finalGrid = this.getGridCopy();
118
-        for (let i = 0; i < coord.length; i++) {
119
-            finalGrid[coord[i].y][coord[i].x] = {
120
-                color: this.currentObject.getColor(),
121
-                isEmpty: false,
122
-            };
123
-        }
116
+        this.currentObject.toGrid(finalGrid, false);
124 117
         return finalGrid;
125 118
     }
126 119
 
@@ -137,19 +130,9 @@ export default class GameLogic {
137 130
         return canLevel;
138 131
     }
139 132
 
140
-    tetrominoToGrid(object: Object, coord : Array<Object>, grid: Array<Array<Object>>) {
141
-        for (let i = 0; i < coord.length; i++) {
142
-            grid[coord[i].y][coord[i].x] = {
143
-                color: object.getColor(),
144
-                isEmpty: false,
145
-            };
146
-        }
147
-    }
148
-
149 133
     freezeTetromino() {
150
-        let coord = this.currentObject.getCellsCoordinates(true);
151
-        this.tetrominoToGrid(this.currentObject, coord, this.currentGrid);
152
-        this.clearLines(this.getLinesToClear(coord));
134
+        this.currentObject.toGrid(this.currentGrid, false);
135
+        this.clearLines(this.getLinesToClear(this.currentObject.getCoordinates()));
153 136
     }
154 137
 
155 138
     clearLines(lines: Array<number>) {
@@ -191,52 +174,6 @@ export default class GameLogic {
191 174
         return rows;
192 175
     }
193 176
 
194
-    isTetrominoPositionValid() {
195
-        let isValid = true;
196
-        let coord = this.currentObject.getCellsCoordinates(true);
197
-        for (let i = 0; i < coord.length; i++) {
198
-            if (coord[i].x >= this.getWidth()
199
-                || coord[i].x < 0
200
-                || coord[i].y >= this.getHeight()
201
-                || coord[i].y < 0
202
-                || !this.currentGrid[coord[i].y][coord[i].x].isEmpty) {
203
-                isValid = false;
204
-                break;
205
-            }
206
-        }
207
-        return isValid;
208
-    }
209
-
210
-    tryMoveTetromino(x: number, y: number) {
211
-        if (x > 1) x = 1; // Prevent moving from more than one tile
212
-        if (x < -1) x = -1;
213
-        if (y > 1) y = 1;
214
-        if (y < -1) y = -1;
215
-        if (x !== 0 && y !== 0) y = 0; // Prevent diagonal movement
216
-
217
-        this.currentObject.move(x, y);
218
-        let isValid = this.isTetrominoPositionValid();
219
-
220
-        if (!isValid && x !== 0)
221
-            this.currentObject.move(-x, 0);
222
-        else if (!isValid && y !== 0) {
223
-            this.currentObject.move(0, -y);
224
-            this.freezeTetromino();
225
-            this.createTetromino();
226
-        } else
227
-            return true;
228
-        return false;
229
-    }
230
-
231
-    tryRotateTetromino() {
232
-        this.currentObject.rotate(true);
233
-        if (!this.isTetrominoPositionValid()) {
234
-            this.currentObject.rotate(false);
235
-            return false;
236
-        }
237
-        return true;
238
-    }
239
-
240 177
     setNewGameTick(level: number) {
241 178
         if (level >= GameLogic.levelTicks.length)
242 179
             return;
@@ -245,8 +182,15 @@ export default class GameLogic {
245 182
         this.gameTickInterval = setInterval(this.onTick, this.gameTick);
246 183
     }
247 184
 
185
+    onFreeze() {
186
+        this.freezeTetromino();
187
+        this.createTetromino();
188
+    }
189
+
248 190
     onTick(callback: Function) {
249
-        this.tryMoveTetromino(0, 1);
191
+        this.currentObject.tryMove(0, 1,
192
+            this.currentGrid, this.getWidth(), this.getHeight(),
193
+            () => this.onFreeze());
250 194
         callback(this.score, this.level, this.getFinalGrid());
251 195
         if (this.canLevelUp()) {
252 196
             this.level++;
@@ -281,8 +225,10 @@ export default class GameLogic {
281 225
     movePressedRepeat(isInitial: boolean, callback: Function, x: number, y: number) {
282 226
         if (!this.canUseInput() || !this.isPressedIn)
283 227
             return;
284
-
285
-        if (this.tryMoveTetromino(x, y)) {
228
+        const moved = this.currentObject.tryMove(x, y,
229
+            this.currentGrid, this.getWidth(), this.getHeight(),
230
+            () => this.onFreeze());
231
+        if (moved) {
286 232
             if (y === 1) {
287 233
                 this.score++;
288 234
                 callback(this.getFinalGrid(), this.score);
@@ -301,7 +247,7 @@ export default class GameLogic {
301 247
         if (!this.canUseInput())
302 248
             return;
303 249
 
304
-        if (this.tryRotateTetromino())
250
+        if (this.currentObject.tryRotate(this.currentGrid, this.getWidth(), this.getHeight()))
305 251
             callback(this.getFinalGrid());
306 252
     }
307 253
 
@@ -312,15 +258,14 @@ export default class GameLogic {
312 258
 
313 259
     generateNextPieces() {
314 260
         while (this.nextPieces.length < this.nextPiecesCount) {
315
-            let shape = Math.floor(Math.random() * 7);
316
-            this.nextPieces.push(new Tetromino(shape, this.colors));
261
+            this.nextPieces.push(new Piece(this.colors));
317 262
         }
318 263
     }
319 264
 
320 265
     createTetromino() {
321 266
         this.pressedOut();
322 267
         this.recoverNextPiece();
323
-        if (!this.isTetrominoPositionValid())
268
+        if (!this.currentObject.isPositionValid(this.currentGrid, this.getWidth(), this.getHeight()))
324 269
             this.endGame(false);
325 270
     }
326 271
 

+ 85
- 0
screens/Tetris/Piece.js View File

@@ -0,0 +1,85 @@
1
+import ShapeL from "./Shapes/ShapeL";
2
+import ShapeI from "./Shapes/ShapeI";
3
+import ShapeJ from "./Shapes/ShapeJ";
4
+import ShapeO from "./Shapes/ShapeO";
5
+import ShapeS from "./Shapes/ShapeS";
6
+import ShapeT from "./Shapes/ShapeT";
7
+import ShapeZ from "./Shapes/ShapeZ";
8
+
9
+export default class Piece {
10
+
11
+    #shapes = [
12
+        ShapeL,
13
+        ShapeI,
14
+        ShapeJ,
15
+        ShapeO,
16
+        ShapeS,
17
+        ShapeT,
18
+        ShapeZ,
19
+    ];
20
+
21
+    #currentShape: Object;
22
+
23
+    constructor(colors: Object) {
24
+        this.#currentShape = new this.#shapes[Math.floor(Math.random() * 7)](colors);
25
+    }
26
+
27
+    toGrid(grid: Array<Array<Object>>, isPreview: boolean) {
28
+        const coord = this.#currentShape.getCellsCoordinates(!isPreview);
29
+        for (let i = 0; i < coord.length; i++) {
30
+            grid[coord[i].y][coord[i].x] = {
31
+                color: this.#currentShape.getColor(),
32
+                isEmpty: false,
33
+            };
34
+        }
35
+    }
36
+
37
+    isPositionValid(grid, width, height) {
38
+        let isValid = true;
39
+        const coord = this.#currentShape.getCellsCoordinates(true);
40
+        for (let i = 0; i < coord.length; i++) {
41
+            if (coord[i].x >= width
42
+                || coord[i].x < 0
43
+                || coord[i].y >= height
44
+                || coord[i].y < 0
45
+                || !grid[coord[i].y][coord[i].x].isEmpty) {
46
+                isValid = false;
47
+                break;
48
+            }
49
+        }
50
+        return isValid;
51
+    }
52
+
53
+    tryMove(x: number, y: number, grid, width, height, freezeCallback: Function) {
54
+        if (x > 1) x = 1; // Prevent moving from more than one tile
55
+        if (x < -1) x = -1;
56
+        if (y > 1) y = 1;
57
+        if (y < -1) y = -1;
58
+        if (x !== 0 && y !== 0) y = 0; // Prevent diagonal movement
59
+
60
+        this.#currentShape.move(x, y);
61
+        let isValid = this.isPositionValid(grid, width, height);
62
+
63
+        if (!isValid && x !== 0)
64
+            this.#currentShape.move(-x, 0);
65
+        else if (!isValid && y !== 0) {
66
+            this.#currentShape.move(0, -y);
67
+            freezeCallback();
68
+        } else
69
+            return true;
70
+        return false;
71
+    }
72
+
73
+    tryRotate(grid, width, height) {
74
+        this.#currentShape.rotate(true);
75
+        if (!this.isPositionValid(grid, width, height)) {
76
+            this.#currentShape.rotate(false);
77
+            return false;
78
+        }
79
+        return true;
80
+    }
81
+
82
+    getCoordinates() {
83
+        return this.#currentShape.getCellsCoordinates(true);
84
+    }
85
+}

+ 65
- 0
screens/Tetris/Shapes/BaseShape.js View File

@@ -0,0 +1,65 @@
1
+// @flow
2
+
3
+/**
4
+ * Abstract class used to represent a BaseShape.
5
+ * Abstract classes do not exist by default in Javascript: we force it by throwing errors in the constructor
6
+ * and in methods to implement
7
+ */
8
+export default class BaseShape {
9
+
10
+    #currentShape: Array<Array<number>>;
11
+    #rotation: number;
12
+    position: Object;
13
+
14
+    constructor() {
15
+        if (this.constructor === BaseShape)
16
+            throw new Error("Abstract class can't be instantiated");
17
+        this.#rotation = 0;
18
+        this.position = {x: 0, y: 0};
19
+        this.#currentShape = this.getShapes()[this.#rotation];
20
+    }
21
+
22
+    getColor(): string {
23
+        throw new Error("Method 'getColor()' must be implemented");
24
+    }
25
+
26
+    getShapes(): Array<Array<Array<number>>> {
27
+        throw new Error("Method 'getShapes()' must be implemented");
28
+    }
29
+
30
+    getCurrentShape() {
31
+        return this.#currentShape;
32
+    }
33
+
34
+    getCellsCoordinates(isAbsolute: boolean) {
35
+        let coordinates = [];
36
+        for (let row = 0; row < this.#currentShape.length; row++) {
37
+            for (let col = 0; col < this.#currentShape[row].length; col++) {
38
+                if (this.#currentShape[row][col] === 1)
39
+                    if (isAbsolute)
40
+                        coordinates.push({x: this.position.x + col, y: this.position.y + row});
41
+                    else
42
+                        coordinates.push({x: col, y: row});
43
+            }
44
+        }
45
+        return coordinates;
46
+    }
47
+
48
+    rotate(isForward: boolean) {
49
+        if (isForward)
50
+            this.#rotation++;
51
+        else
52
+            this.#rotation--;
53
+        if (this.#rotation > 3)
54
+            this.#rotation = 0;
55
+        else if (this.#rotation < 0)
56
+            this.#rotation = 3;
57
+        this.#currentShape = this.getShapes()[this.#rotation];
58
+    }
59
+
60
+    move(x: number, y: number) {
61
+        this.position.x += x;
62
+        this.position.y += y;
63
+    }
64
+
65
+}

+ 47
- 0
screens/Tetris/Shapes/ShapeI.js View File

@@ -0,0 +1,47 @@
1
+// @flow
2
+
3
+import BaseShape from "./BaseShape";
4
+
5
+export default class ShapeI extends BaseShape {
6
+
7
+    #colors: Object;
8
+
9
+    constructor(colors: Object) {
10
+        super();
11
+        this.position.x = 3;
12
+        this.#colors = colors;
13
+    }
14
+
15
+    getColor(): string {
16
+        return this.#colors.tetrisI;
17
+    }
18
+
19
+    getShapes() {
20
+        return [
21
+            [
22
+                [0, 0, 0, 0],
23
+                [1, 1, 1, 1],
24
+                [0, 0, 0, 0],
25
+                [0, 0, 0, 0],
26
+            ],
27
+            [
28
+                [0, 0, 1, 0],
29
+                [0, 0, 1, 0],
30
+                [0, 0, 1, 0],
31
+                [0, 0, 1, 0],
32
+            ],
33
+            [
34
+                [0, 0, 0, 0],
35
+                [0, 0, 0, 0],
36
+                [1, 1, 1, 1],
37
+                [0, 0, 0, 0],
38
+            ],
39
+            [
40
+                [0, 1, 0, 0],
41
+                [0, 1, 0, 0],
42
+                [0, 1, 0, 0],
43
+                [0, 1, 0, 0],
44
+            ],
45
+        ];
46
+    }
47
+}

+ 43
- 0
screens/Tetris/Shapes/ShapeJ.js View File

@@ -0,0 +1,43 @@
1
+// @flow
2
+
3
+import BaseShape from "./BaseShape";
4
+
5
+export default class ShapeJ extends BaseShape {
6
+
7
+    #colors: Object;
8
+
9
+    constructor(colors: Object) {
10
+        super();
11
+        this.position.x = 3;
12
+        this.#colors = colors;
13
+    }
14
+
15
+    getColor(): string {
16
+        return this.#colors.tetrisJ;
17
+    }
18
+
19
+    getShapes() {
20
+        return [
21
+            [
22
+                [1, 0, 0],
23
+                [1, 1, 1],
24
+                [0, 0, 0],
25
+            ],
26
+            [
27
+                [0, 1, 1],
28
+                [0, 1, 0],
29
+                [0, 1, 0],
30
+            ],
31
+            [
32
+                [0, 0, 0],
33
+                [1, 1, 1],
34
+                [0, 0, 1],
35
+            ],
36
+            [
37
+                [0, 1, 0],
38
+                [0, 1, 0],
39
+                [1, 1, 0],
40
+            ],
41
+        ];
42
+    }
43
+}

+ 43
- 0
screens/Tetris/Shapes/ShapeL.js View File

@@ -0,0 +1,43 @@
1
+// @flow
2
+
3
+import BaseShape from "./BaseShape";
4
+
5
+export default class ShapeL extends BaseShape {
6
+
7
+    #colors: Object;
8
+
9
+    constructor(colors: Object) {
10
+        super();
11
+        this.position.x = 3;
12
+        this.#colors = colors;
13
+    }
14
+
15
+    getColor(): string {
16
+        return this.#colors.tetrisL;
17
+    }
18
+
19
+    getShapes() {
20
+        return [
21
+            [
22
+                [0, 0, 1],
23
+                [1, 1, 1],
24
+                [0, 0, 0],
25
+            ],
26
+            [
27
+                [0, 1, 0],
28
+                [0, 1, 0],
29
+                [0, 1, 1],
30
+            ],
31
+            [
32
+                [0, 0, 0],
33
+                [1, 1, 1],
34
+                [1, 0, 0],
35
+            ],
36
+            [
37
+                [1, 1, 0],
38
+                [0, 1, 0],
39
+                [0, 1, 0],
40
+            ],
41
+        ];
42
+    }
43
+}

+ 39
- 0
screens/Tetris/Shapes/ShapeO.js View File

@@ -0,0 +1,39 @@
1
+// @flow
2
+
3
+import BaseShape from "./BaseShape";
4
+
5
+export default class ShapeO extends BaseShape {
6
+
7
+    #colors: Object;
8
+
9
+    constructor(colors: Object) {
10
+        super();
11
+        this.position.x = 4;
12
+        this.#colors = colors;
13
+    }
14
+
15
+    getColor(): string {
16
+        return this.#colors.tetrisO;
17
+    }
18
+
19
+    getShapes() {
20
+        return [
21
+            [
22
+                [1, 1],
23
+                [1, 1],
24
+            ],
25
+            [
26
+                [1, 1],
27
+                [1, 1],
28
+            ],
29
+            [
30
+                [1, 1],
31
+                [1, 1],
32
+            ],
33
+            [
34
+                [1, 1],
35
+                [1, 1],
36
+            ],
37
+        ];
38
+    }
39
+}

+ 43
- 0
screens/Tetris/Shapes/ShapeS.js View File

@@ -0,0 +1,43 @@
1
+// @flow
2
+
3
+import BaseShape from "./BaseShape";
4
+
5
+export default class ShapeS extends BaseShape {
6
+
7
+    #colors: Object;
8
+
9
+    constructor(colors: Object) {
10
+        super();
11
+        this.position.x = 3;
12
+        this.#colors = colors;
13
+    }
14
+
15
+    getColor(): string {
16
+        return this.#colors.tetrisS;
17
+    }
18
+
19
+    getShapes() {
20
+        return [
21
+            [
22
+                [0, 1, 1],
23
+                [1, 1, 0],
24
+                [0, 0, 0],
25
+            ],
26
+            [
27
+                [0, 1, 0],
28
+                [0, 1, 1],
29
+                [0, 0, 1],
30
+            ],
31
+            [
32
+                [0, 0, 0],
33
+                [0, 1, 1],
34
+                [1, 1, 0],
35
+            ],
36
+            [
37
+                [1, 0, 0],
38
+                [1, 1, 0],
39
+                [0, 1, 0],
40
+            ],
41
+        ];
42
+    }
43
+}

+ 43
- 0
screens/Tetris/Shapes/ShapeT.js View File

@@ -0,0 +1,43 @@
1
+// @flow
2
+
3
+import BaseShape from "./BaseShape";
4
+
5
+export default class ShapeT extends BaseShape {
6
+
7
+    #colors: Object;
8
+
9
+    constructor(colors: Object) {
10
+        super();
11
+        this.position.x = 3;
12
+        this.#colors = colors;
13
+    }
14
+
15
+    getColor(): string {
16
+        return this.#colors.tetrisT;
17
+    }
18
+
19
+    getShapes() {
20
+        return [
21
+            [
22
+                [0, 1, 0],
23
+                [1, 1, 1],
24
+                [0, 0, 0],
25
+            ],
26
+            [
27
+                [0, 1, 0],
28
+                [0, 1, 1],
29
+                [0, 1, 0],
30
+            ],
31
+            [
32
+                [0, 0, 0],
33
+                [1, 1, 1],
34
+                [0, 1, 0],
35
+            ],
36
+            [
37
+                [0, 1, 0],
38
+                [1, 1, 0],
39
+                [0, 1, 0],
40
+            ],
41
+        ];
42
+    }
43
+}

+ 43
- 0
screens/Tetris/Shapes/ShapeZ.js View File

@@ -0,0 +1,43 @@
1
+// @flow
2
+
3
+import BaseShape from "./BaseShape";
4
+
5
+export default class ShapeZ extends BaseShape {
6
+
7
+    #colors: Object;
8
+
9
+    constructor(colors: Object) {
10
+        super();
11
+        this.position.x = 3;
12
+        this.#colors = colors;
13
+    }
14
+
15
+    getColor(): string {
16
+        return this.#colors.tetrisZ;
17
+    }
18
+
19
+    getShapes() {
20
+        return [
21
+            [
22
+                [1, 1, 0],
23
+                [0, 1, 1],
24
+                [0, 0, 0],
25
+            ],
26
+            [
27
+                [0, 0, 1],
28
+                [0, 1, 1],
29
+                [0, 1, 0],
30
+            ],
31
+            [
32
+                [0, 0, 0],
33
+                [1, 1, 0],
34
+                [0, 1, 1],
35
+            ],
36
+            [
37
+                [0, 1, 0],
38
+                [1, 1, 0],
39
+                [1, 0, 0],
40
+            ],
41
+        ];
42
+    }
43
+}

+ 1
- 1
screens/Tetris/TetrisScreen.js View File

@@ -253,7 +253,7 @@ class TetrisScreen extends React.Component<Props, State> {
253 253
                     right: 5,
254 254
                 }}>
255 255
                     <Preview
256
-                        next={this.logic.getNextPieces()}
256
+                        next={this.logic.getNextPiecesPreviews()}
257 257
                     />
258 258
                 </View>
259 259
                 <View style={{

+ 0
- 230
screens/Tetris/Tetromino.js View File

@@ -1,230 +0,0 @@
1
-// @flow
2
-
3
-export default class Tetromino {
4
-
5
-    static types = {
6
-        'I': 0,
7
-        'O': 1,
8
-        'T': 2,
9
-        'S': 3,
10
-        'Z': 4,
11
-        'J': 5,
12
-        'L': 6,
13
-    };
14
-
15
-    static shapes = [
16
-        [
17
-            [
18
-                [0, 0, 0, 0],
19
-                [1, 1, 1, 1],
20
-                [0, 0, 0, 0],
21
-                [0, 0, 0, 0],
22
-            ],
23
-            [
24
-                [1, 1],
25
-                [1, 1],
26
-            ],
27
-            [
28
-                [0, 1, 0],
29
-                [1, 1, 1],
30
-                [0, 0, 0],
31
-            ],
32
-            [
33
-                [0, 1, 1],
34
-                [1, 1, 0],
35
-                [0, 0, 0],
36
-            ],
37
-            [
38
-                [1, 1, 0],
39
-                [0, 1, 1],
40
-                [0, 0, 0],
41
-            ],
42
-            [
43
-                [1, 0, 0],
44
-                [1, 1, 1],
45
-                [0, 0, 0],
46
-            ],
47
-            [
48
-                [0, 0, 1],
49
-                [1, 1, 1],
50
-                [0, 0, 0],
51
-            ],
52
-        ],
53
-        [
54
-            [
55
-                [0, 0, 1, 0],
56
-                [0, 0, 1, 0],
57
-                [0, 0, 1, 0],
58
-                [0, 0, 1, 0],
59
-            ],
60
-            [
61
-                [1, 1],
62
-                [1, 1],
63
-            ],
64
-            [
65
-                [0, 1, 0],
66
-                [0, 1, 1],
67
-                [0, 1, 0],
68
-            ],
69
-            [
70
-                [0, 1, 0],
71
-                [0, 1, 1],
72
-                [0, 0, 1],
73
-            ],
74
-            [
75
-                [0, 0, 1],
76
-                [0, 1, 1],
77
-                [0, 1, 0],
78
-            ],
79
-            [
80
-                [0, 1, 1],
81
-                [0, 1, 0],
82
-                [0, 1, 0],
83
-            ],
84
-            [
85
-                [0, 1, 0],
86
-                [0, 1, 0],
87
-                [0, 1, 1],
88
-            ],
89
-        ],
90
-        [
91
-            [
92
-                [0, 0, 0, 0],
93
-                [0, 0, 0, 0],
94
-                [1, 1, 1, 1],
95
-                [0, 0, 0, 0],
96
-            ],
97
-            [
98
-                [1, 1],
99
-                [1, 1],
100
-            ],
101
-            [
102
-                [0, 0, 0],
103
-                [1, 1, 1],
104
-                [0, 1, 0],
105
-            ],
106
-            [
107
-                [0, 0, 0],
108
-                [0, 1, 1],
109
-                [1, 1, 0],
110
-            ],
111
-            [
112
-                [0, 0, 0],
113
-                [1, 1, 0],
114
-                [0, 1, 1],
115
-            ],
116
-            [
117
-                [0, 0, 0],
118
-                [1, 1, 1],
119
-                [0, 0, 1],
120
-            ],
121
-            [
122
-                [0, 0, 0],
123
-                [1, 1, 1],
124
-                [1, 0, 0],
125
-            ],
126
-        ],
127
-        [
128
-            [
129
-                [0, 1, 0, 0],
130
-                [0, 1, 0, 0],
131
-                [0, 1, 0, 0],
132
-                [0, 1, 0, 0],
133
-            ],
134
-            [
135
-                [1, 1],
136
-                [1, 1],
137
-            ],
138
-            [
139
-                [0, 1, 0],
140
-                [1, 1, 0],
141
-                [0, 1, 0],
142
-            ],
143
-            [
144
-                [1, 0, 0],
145
-                [1, 1, 0],
146
-                [0, 1, 0],
147
-            ],
148
-            [
149
-                [0, 1, 0],
150
-                [1, 1, 0],
151
-                [1, 0, 0],
152
-            ],
153
-            [
154
-                [0, 1, 0],
155
-                [0, 1, 0],
156
-                [1, 1, 0],
157
-            ],
158
-            [
159
-                [1, 1, 0],
160
-                [0, 1, 0],
161
-                [0, 1, 0],
162
-            ],
163
-        ],
164
-    ];
165
-
166
-    static colors: Object;
167
-
168
-    currentType: number;
169
-    currentShape: Object;
170
-    currentRotation: number;
171
-    position: Object;
172
-    colors: Object;
173
-
174
-    constructor(type: number, colors: Object) {
175
-        this.currentType = type;
176
-        this.currentRotation = 0;
177
-        this.currentShape = Tetromino.shapes[this.currentRotation][type];
178
-        this.position = {x: 0, y: 0};
179
-        if (this.currentType === Tetromino.types.O)
180
-            this.position.x = 4;
181
-        else
182
-            this.position.x = 3;
183
-        this.colors = colors;
184
-        Tetromino.colors = [
185
-            colors.tetrisI,
186
-            colors.tetrisO,
187
-            colors.tetrisT,
188
-            colors.tetrisS,
189
-            colors.tetrisZ,
190
-            colors.tetrisJ,
191
-            colors.tetrisL,
192
-        ];
193
-    }
194
-
195
-    getColor() {
196
-        return Tetromino.colors[this.currentType];
197
-    }
198
-
199
-    getCellsCoordinates(isAbsolute: boolean) {
200
-        let coordinates = [];
201
-        for (let row = 0; row < this.currentShape.length; row++) {
202
-            for (let col = 0; col < this.currentShape[row].length; col++) {
203
-                if (this.currentShape[row][col] === 1)
204
-                    if (isAbsolute)
205
-                        coordinates.push({x: this.position.x + col, y: this.position.y + row});
206
-                    else
207
-                        coordinates.push({x: col, y: row});
208
-            }
209
-        }
210
-        return coordinates;
211
-    }
212
-
213
-    rotate(isForward: boolean) {
214
-        if (isForward)
215
-            this.currentRotation++;
216
-        else
217
-            this.currentRotation--;
218
-        if (this.currentRotation > 3)
219
-            this.currentRotation = 0;
220
-        else if (this.currentRotation < 0)
221
-            this.currentRotation = 3;
222
-        this.currentShape = Tetromino.shapes[this.currentRotation][this.currentType];
223
-    }
224
-
225
-    move(x: number, y: number) {
226
-        this.position.x += x;
227
-        this.position.y += y;
228
-    }
229
-
230
-}

+ 104
- 0
screens/Tetris/__tests__/Tetromino.test.js View File

@@ -0,0 +1,104 @@
1
+import React from 'react';
2
+import BaseShape from "../Shapes/BaseShape";
3
+import ShapeI from "../Shapes/ShapeI";
4
+
5
+const colors = {
6
+    tetrisI: '#000001',
7
+    tetrisO: '#000002',
8
+    tetrisT: '#000003',
9
+    tetrisS: '#000004',
10
+    tetrisZ: '#000005',
11
+    tetrisJ: '#000006',
12
+    tetrisL: '#000007',
13
+};
14
+
15
+test('constructor', () => {
16
+    expect(() => new BaseShape()).toThrow(Error);
17
+
18
+    let T = new ShapeI(colors);
19
+    expect(T.position.y).toBe(0);
20
+    expect(T.position.x).toBe(3);
21
+    expect(T.getCurrentShape()).toStrictEqual(T.getShapes()[0]);
22
+    expect(T.getColor()).toBe(colors.tetrisI);
23
+});
24
+
25
+test("move", () => {
26
+    let T = new ShapeI(colors);
27
+    T.move(0, 1);
28
+    expect(T.position.x).toBe(3);
29
+    expect(T.position.y).toBe(1);
30
+    T.move(1, 0);
31
+    expect(T.position.x).toBe(4);
32
+    expect(T.position.y).toBe(1);
33
+    T.move(1, 1);
34
+    expect(T.position.x).toBe(5);
35
+    expect(T.position.y).toBe(2);
36
+    T.move(2, 2);
37
+    expect(T.position.x).toBe(7);
38
+    expect(T.position.y).toBe(4);
39
+    T.move(-1, -1);
40
+    expect(T.position.x).toBe(6);
41
+    expect(T.position.y).toBe(3);
42
+});
43
+
44
+test('rotate', () => {
45
+    let T = new ShapeI(colors);
46
+    T.rotate(true);
47
+    expect(T.getCurrentShape()).toStrictEqual(T.getShapes()[1]);
48
+    T.rotate(true);
49
+    expect(T.getCurrentShape()).toStrictEqual(T.getShapes()[2]);
50
+    T.rotate(true);
51
+    expect(T.getCurrentShape()).toStrictEqual(T.getShapes()[3]);
52
+    T.rotate(true);
53
+    expect(T.getCurrentShape()).toStrictEqual(T.getShapes()[0]);
54
+    T.rotate(false);
55
+    expect(T.getCurrentShape()).toStrictEqual(T.getShapes()[3]);
56
+    T.rotate(false);
57
+    expect(T.getCurrentShape()).toStrictEqual(T.getShapes()[2]);
58
+    T.rotate(false);
59
+    expect(T.getCurrentShape()).toStrictEqual(T.getShapes()[1]);
60
+    T.rotate(false);
61
+    expect(T.getCurrentShape()).toStrictEqual(T.getShapes()[0]);
62
+});
63
+
64
+test('getCellsCoordinates', () => {
65
+    let T = new ShapeI(colors);
66
+    expect(T.getCellsCoordinates(false)).toStrictEqual([
67
+        {x: 0, y: 1},
68
+        {x: 1, y: 1},
69
+        {x: 2, y: 1},
70
+        {x: 3, y: 1},
71
+    ]);
72
+    expect(T.getCellsCoordinates(true)).toStrictEqual([
73
+        {x: 3, y: 1},
74
+        {x: 4, y: 1},
75
+        {x: 5, y: 1},
76
+        {x: 6, y: 1},
77
+    ]);
78
+    T.move(1, 1);
79
+    expect(T.getCellsCoordinates(false)).toStrictEqual([
80
+        {x: 0, y: 1},
81
+        {x: 1, y: 1},
82
+        {x: 2, y: 1},
83
+        {x: 3, y: 1},
84
+    ]);
85
+    expect(T.getCellsCoordinates(true)).toStrictEqual([
86
+        {x: 4, y: 2},
87
+        {x: 5, y: 2},
88
+        {x: 6, y: 2},
89
+        {x: 7, y: 2},
90
+    ]);
91
+    T.rotate(true);
92
+    expect(T.getCellsCoordinates(false)).toStrictEqual([
93
+        {x: 2, y: 0},
94
+        {x: 2, y: 1},
95
+        {x: 2, y: 2},
96
+        {x: 2, y: 3},
97
+    ]);
98
+    expect(T.getCellsCoordinates(true)).toStrictEqual([
99
+        {x: 6, y: 1},
100
+        {x: 6, y: 2},
101
+        {x: 6, y: 3},
102
+        {x: 6, y: 4},
103
+    ]);
104
+});

Loading…
Cancel
Save