Skip to content

Commit fd3ba0d

Browse files
committed
feat: finish tetris
1 parent 63d4d0e commit fd3ba0d

28 files changed

+406
-111
lines changed

Tetris/App.tsx

Lines changed: 40 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,69 @@
11
import React, { useEffect, useReducer, useState } from "react";
22
import { useInterval } from "usehooks-ts";
33
import Block from "./components/Block";
4-
import { EMPTY_BLOCK } from "./constants";
5-
import { canMoveDown, cleanRow, hasBlock, mergeBlocks } from "./utils";
4+
import {
5+
ADD_BLOCK,
6+
CLEAN_ROW,
7+
DOWN,
8+
EMPTY_BLOCK,
9+
INITIAL_SCREEN,
10+
MERGE_BLOCK,
11+
MOVE_LEFT,
12+
MOVE_RIGHT,
13+
ROTATE,
14+
} from "./constants";
15+
import { canMoveDown, hasBlock, moveLatest } from "./utils";
616
import { useBindEvent } from "./hooks";
7-
import { reducer } from "./reducer";
17+
import { moveBlockReducer } from "./reducers/moveBlock";
18+
import { bgBlockReducer } from "./reducers/bgBlock";
819

920
import "./styles.less";
1021

1122
function App() {
1223
const [speed, setSpeed] = useState(1000);
13-
const [moveBlock, dispatch] = useReducer(reducer, [...EMPTY_BLOCK]);
14-
const [stickBlock, setStickBlock] = useState([
15-
0b0000000000, 0b0000000000, 0b0000000000, 0b0000000000, 0b0000000000,
16-
0b0000000000, 0b0000000000, 0b0000000000, 0b0000000000, 0b0000000000,
17-
0b0000000000, 0b0000000000, 0b0000000000, 0b0000000000, 0b0000000000,
18-
0b0000000000, 0b0000000000, 0b0000000000, 0b0000000000, 0b0000000000,
24+
const [moveBlock, moveBlockDispatch] = useReducer(moveBlockReducer, [
25+
...EMPTY_BLOCK,
26+
]);
27+
const [bgBlock, bgBlockDispatch] = useReducer(bgBlockReducer, [
28+
...EMPTY_BLOCK,
1929
]);
2030
useInterval(() => {
31+
if (!canMoveDown(moveBlock, bgBlock)) {
32+
bgBlockDispatch({ type: MERGE_BLOCK, moveBlock });
33+
}
2134
if (!hasBlock(moveBlock)) {
22-
dispatch({ type: "ADD_BLOCK", stickBlock });
35+
moveBlockDispatch({ type: ADD_BLOCK, bgBlock });
2336
} else {
24-
dispatch({ type: "DOWN", stickBlock });
37+
moveBlockDispatch({ type: DOWN, bgBlock });
2538
}
39+
bgBlockDispatch({ type: CLEAN_ROW });
2640
}, speed);
27-
useEffect(() => {
28-
if (!canMoveDown(moveBlock, stickBlock)) {
29-
setStickBlock(mergeBlocks(moveBlock, stickBlock));
30-
}
31-
}, [moveBlock]);
32-
useEffect(() => {
33-
setStickBlock(cleanRow(stickBlock));
34-
}, [stickBlock]);
3541
useBindEvent({
3642
moveLeft: () => {
37-
dispatch({ type: "MOVE_LEFT", stickBlock });
43+
moveBlockDispatch({ type: MOVE_LEFT, bgBlock });
3844
},
3945
moveRight: () => {
40-
dispatch({ type: "MOVE_RIGHT", stickBlock });
46+
moveBlockDispatch({ type: MOVE_RIGHT, bgBlock });
4147
},
4248
moveDown: () => {
43-
dispatch({ type: "DOWN", stickBlock });
49+
moveBlockDispatch({ type: DOWN, bgBlock });
50+
if (!canMoveDown(moveBlock, bgBlock)) {
51+
bgBlockDispatch({ type: MERGE_BLOCK, moveBlock });
52+
}
53+
},
54+
moveDownImmediate: () => {
55+
const newMoveBlock = moveLatest(moveBlock, bgBlock);
56+
moveBlockDispatch({ type: INITIAL_SCREEN });
57+
bgBlockDispatch({ type: MERGE_BLOCK, moveBlock: newMoveBlock });
58+
},
59+
rotate: () => {
60+
moveBlockDispatch({ type: ROTATE });
4461
},
45-
rotate: () => {},
46-
moveDownImmediate: () => {},
4762
});
4863
return (
4964
<div className="page">
5065
<Block data={moveBlock} />
51-
<Block data={stickBlock} />
66+
<Block className="bg" data={bgBlock} />
5267
</div>
5368
);
5469
}

Tetris/README.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Dev Step
2+
3+
1. how to express?
4+
2D Array like this
5+
```js
6+
[
7+
0b0000000000,
8+
0b0000000000,
9+
0b0000000000,
10+
0b0000000000,
11+
0b0000000000,
12+
0b0000000000,
13+
0b0000000000,
14+
0b0000000000,
15+
0b0000000000,
16+
0b0000000000,
17+
0b0000000000,
18+
0b0000000000,
19+
0b0000000000,
20+
0b0000000000,
21+
0b0000000000,
22+
0b0000000000,
23+
0b0000000000,
24+
0b0000000000,
25+
0b0000000000,
26+
0b0000000000,
27+
]
28+
```
29+
30+
2. how to move
31+
move left: `0b0000000000 >> 1`
32+
move right: `0b0000000000 << 1`
33+
34+
3. how to remove
35+
4. how to rotate
36+
37+
# Reference
38+
39+
[俄罗斯方块实现思路【渡一教育】](https://www.bilibili.com/video/BV1YG411z7V2/?spm_id_from=333.337.search-card.all.click&vd_source=87f758b0f5b48f523e2bb91356679759)

Tetris/components/Block.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
import React from "react";
22
import Row from "./Row";
3+
import classNames from "classnames";
34

45
interface IProps {
56
data: number[];
7+
className?: string;
68
}
79

8-
function Block({ data }: IProps) {
10+
function Block({ data, className }: IProps) {
911
return (
10-
<div className="container">
12+
<div className={classNames("container", className)}>
1113
{data.map((row, i) => (
1214
<Row key={i} data={row} y={i} />
1315
))}

Tetris/components/Row.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import React from "react";
22
import classnames from "classnames";
33
import { binaryFmt } from "../utils";
4+
import { SIZE } from "../constants";
45

56
interface IProps {
67
data: number;
@@ -20,8 +21,8 @@ function Row({ data, y }: IProps) {
2021
+col ? "block" : ""
2122
)}
2223
style={{
23-
top: y * 20,
24-
left: x * 20,
24+
top: y * SIZE,
25+
left: x * SIZE,
2526
}}
2627
/>
2728
))}

Tetris/constants.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,13 @@ export const EMPTY_BLOCK = [
55
0b0000000000, 0b0000000000, 0b0000000000, 0b0000000000, 0b0000000000,
66
];
77

8-
export const DOWN = "DOWN";
8+
export const SIZE = 40;
9+
export const INITIAL_SCREEN = "INITIAL_SCREEN";
10+
export const DOWN_IMMEDIATE = "DOWN_IMMEDIATE";
911
export const ADD_BLOCK = "ADD_BLOCK";
1012
export const MOVE_LEFT = "MOVE_LEFT";
1113
export const MOVE_RIGHT = "MOVE_RIGHT";
14+
export const DOWN = "DOWN";
15+
export const ROTATE = "ROTATE";
1216
export const CLEAN_ROW = "CLEAN_ROW";
17+
export const MERGE_BLOCK = "MERGE_BLOCK";

Tetris/hooks.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,22 @@
1-
import { useEffect } from "react";
21
import { useEventListener } from "usehooks-ts";
32

3+
interface IProps {
4+
moveLeft: () => void;
5+
moveRight: () => void;
6+
moveDown: () => void;
7+
moveDownImmediate: () => void;
8+
rotate: () => void;
9+
}
10+
11+
const event = "keydown";
12+
413
export function useBindEvent({
514
moveLeft,
615
moveRight,
716
moveDown,
817
moveDownImmediate,
918
rotate,
10-
}) {
11-
const event = "keydown";
19+
}: IProps) {
1220
function cb(e: KeyboardEvent) {
1321
if (e.code === "ArrowLeft") {
1422
moveLeft();

Tetris/index.html

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,13 @@
33
<head>
44
<meta charset="UTF-8">
55
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<link rel="apple-touch-icon" sizes="180x180" href="/favicon/apple-touch-icon.png">
7+
<link rel="icon" type="image/png" sizes="32x32" href="/favicon/favicon-32x32.png">
8+
<link rel="icon" type="image/png" sizes="16x16" href="/favicon/favicon-16x16.png">
9+
<link rel="manifest" href="/favicon/site.webmanifest">
10+
<link rel="mask-icon" href="/favicon/safari-pinned-tab.svg" color="#5bbad5">
11+
<meta name="msapplication-TileColor" content="#da532c">
12+
<meta name="theme-color" content="#ffffff">
613
<title>Tetris</title>
714
</head>
815
<body>

Tetris/reducer.ts

Lines changed: 0 additions & 46 deletions
This file was deleted.

Tetris/reducers/bgBlock.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { CLEAN_ROW, MERGE_BLOCK } from "../constants";
2+
import { cleanRow, mergeBlocks } from "../utils";
3+
4+
export interface BaseAction {
5+
readonly type: string;
6+
}
7+
8+
export interface Action extends BaseAction {
9+
readonly moveBlock?: number[];
10+
}
11+
12+
export const bgBlockReducer = (state: number[], action: Action) => {
13+
switch (action.type) {
14+
case CLEAN_ROW:
15+
return cleanRow(state);
16+
case MERGE_BLOCK:
17+
if (action.moveBlock) {
18+
return mergeBlocks(state, action.moveBlock);
19+
}
20+
return state;
21+
default:
22+
return state;
23+
}
24+
};

Tetris/reducers/moveBlock.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import {
2+
ADD_BLOCK,
3+
DOWN,
4+
EMPTY_BLOCK,
5+
INITIAL_SCREEN,
6+
MOVE_LEFT,
7+
MOVE_RIGHT,
8+
ROTATE,
9+
} from "../constants";
10+
import {
11+
addRandomBlock,
12+
canMoveDown,
13+
canMoveLeft,
14+
canMoveRight,
15+
moveDown,
16+
moveLatest,
17+
moveLeft,
18+
moveRight,
19+
rotateBlock,
20+
} from "../utils";
21+
22+
export interface BaseAction {
23+
readonly type: string;
24+
}
25+
26+
export interface Action extends BaseAction {
27+
readonly bgBlock?: number[];
28+
}
29+
30+
export const moveBlockReducer = (state: number[], action: Action) => {
31+
switch (action.type) {
32+
case INITIAL_SCREEN:
33+
return addRandomBlock(EMPTY_BLOCK);
34+
case ROTATE:
35+
return rotateBlock(state);
36+
case DOWN:
37+
if (canMoveDown(state, action?.bgBlock)) {
38+
return moveDown(state);
39+
}
40+
return addRandomBlock(EMPTY_BLOCK);
41+
case ADD_BLOCK:
42+
return addRandomBlock(EMPTY_BLOCK);
43+
case MOVE_LEFT:
44+
if (canMoveLeft(state, action?.bgBlock)) {
45+
return moveLeft(state);
46+
}
47+
return state;
48+
case MOVE_RIGHT:
49+
if (canMoveRight(state, action.bgBlock)) {
50+
return moveRight(state);
51+
}
52+
return state;
53+
default:
54+
return state;
55+
}
56+
};

0 commit comments

Comments
 (0)