-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmino.js
134 lines (111 loc) · 3.14 KB
/
mino.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// Lookup for piece shape and rotation
// values are arrays of rotated shapes
// each of these is an array of block x/y pairs
const SHAPE_TABLE = {
1: [
[[1,0], [1,1], [1,2]],
[[0,1], [1,1], [2,1]]
],
2: [
[[1,0],[1,1],[2,1]],
[[2,1],[1,1],[1,2]],
[[1,1],[2,1],[2,2]],
[[0,1],[1,1],[1,0]],
]
}
class Mino {
constructor (shape, x, y) {
this.rotation = 0;
this.x = x
this.y = y
// is first arg an array (presumably of blocks)
if(shape.map) {
this.blocks = shape
} else {
// or its a shape identifier
// we need to store an origin position
this.shape = shape;
this.rebuildBlocks()
}
this.landed = false;
}
blocksFromShape (shape, x, y) {
const rotation = SHAPE_TABLE[shape][this.rotation]
return rotation.map((pair) => new Block(pair[0] + x, pair[1] + y, shape))
}
rebuildBlocks () {
this.blocks = this.blocksFromShape(this.shape, this.x, this.y)
}
rotateCW () {
this.rotation = this.rotation + 1 === SHAPE_TABLE[this.shape].length ? 0 : this.rotation + 1;
this.rebuildBlocks()
}
// rotateCCW () {
// this.rotation = (this.rotation === 0) ? SHAPE_TABLE[this.shape].length - 1 ? 0
// this.blocks = this.blocksFromShape(this.shape);
// }
static getRandom () {
const i = Math.floor(Math.random() * 2) + 1;
return new Mino(i, 3, 0)
}
moveDown (instant) {
if(this.y !== undefined) {
this.y ++;
}
this.blocks.forEach((block) => {
block.moveDown();
if(instant) {
block.entity.y = block.y;
}
});
}
moveLeft () {
if(this.x) this.x--;
this.blocks.forEach((b) => b.moveLeft());
}
moveRight () {
if(this.x) this.x++;
this.blocks.forEach((b) => b.moveRight());
}
cellsBelow () {
return this.blocks
// all cells below a block's position
.map((block) => [block.x, block.y + 1])
// no occupied by another block in this mino
.filter((cell) => !this.blocks.some((block) => block.x === cell[0] && block.y === cell[1])
)
}
onBottom () {
return this.blocks.some((block) => block.y === BOARD_HEIGHT -1)
}
// Evaluate the result of clearing one or more blocks from this mino
// Return array of 0 or more mino
// Remaining blocks are divided into contigious groups
split (removedBlocks) {
const groups = []
// for each existing block
this.blocks.forEach((block) => {
// is this a block we're discarding
if(removedBlocks.includes(block)) {
// do nothing. block not added to any group
return
}
if(!this.blocks.includes(block)) {
// its not one of this mino's blocks
return
}
// is this block touching a block in any other group?
const groupTouchingBlock = groups.find((group) => {
return !! group.find((groupBlock) => block.touches(groupBlock))
})
if(groupTouchingBlock) {
// add to the group that included a block touching the block in question
groupTouchingBlock.push(block)
} else {
// start a new group
groups.push([block])
}
})
return groups.map((group) => new Mino(group))
}
}