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
|
package tris
// As at the bottom of https://tetris.fandom.com/wiki/SRS but Y inverse because we start Y at the top
type Kicks map[Rotation][]Point
// Kics for all pieces except I and O pieces
var K3CW = Kicks{
0: {{X:0, Y:0}, {X:-1, Y:0}, {X:-1, Y: -1}, {X:0, Y:2}, {X:-1, Y:2}},
1: {{X:0, Y:0}, {X:1, Y:0}, {X:1, Y: 1}, {X:0, Y:-2}, {X:1, Y:-2}},
2: {{X:0, Y:0}, {X:1, Y:0}, {X:1, Y: -1}, {X:0, Y:2}, {X:1, Y:2}},
3: {{X:0, Y:0}, {X:-1, Y:0}, {X:-1, Y: 1}, {X:0, Y:-2}, {X:-1, Y:-2}},
}
// Long Bar (I piece) Kicks
var LCW = Kicks{
0: {{X:0, Y:0}, {X:-2, Y:0}, {X:1, Y: 0}, {X:-2, Y:1}, {X:1, Y:-2}},
1: {{X:0, Y:0}, {X:-1, Y:0}, {X:2, Y: 0}, {X:-1, Y:-2}, {X:2, Y:1}},
2: {{X:0, Y:0}, {X:2, Y:0}, {X:-1, Y: 0}, {X:2, Y:-1}, {X:-1, Y:2}},
3: {{X:0, Y:0}, {X:1, Y:0}, {X:-2, Y: 0}, {X:1, Y:2}, {X:-2, Y:-1}},
}
// Try all possible kicks
func (ks Kicks) Try(rot Rotation, reverse bool, p Placement, f Field) (np Placement) {
orot := (rot + 3)%4
if reverse { // for going backwards, you start from one more
rot--
orot = (rot + 1)%4
}
for _, k := range ks[rot] {
np = p
x, y := k.X, k.Y
if reverse {
x, y = -x, -y
}
np.X, np.Y = p.X+x, p.Y+y
if !np.Collide(f) {
return np
}
}
p.Rot = orot
return p
}
// Floor checks if the piece touches something underneath it
func (p Placement) Floor(f Field) bool {
fp := p
fp.Y++
return fp.Collide(f)
}
// CW checks if the rotation from r to nr is a Clockwise rotation
func (r Rotation) CW(nr Rotation) bool {
r += 4
return (r - nr)%4 == 1 // if nr is 1 modulo 4 higher than r, it is a CW rotation
}
// Move tries the move indicated by the parameters, applies kicks to fix when it doesn't work,
// and returns if the piece is on the floor or topping out
func (p Placement) Move(f Field, rot Rotation, x, y int) (np Placement, floor, topout bool) {
np = p
np.Rot = rot
np.X = x
np.Y = y
if !np.Collide(f) { // free air
return np, np.Floor(f), false
}
// start handling kicks
switch p.piece {
case IPiece:
np = LCW.Try(rot, np.Rot.CW(rot), np, f)
case JPiece, SPiece, ZPiece, TPiece, LPiece:
np = K3CW.Try(rot, np.Rot.CW(rot), np, f)
}
np = p // last resort reset p
if np.Floor(f) && np.Y < 0 {
return np, true, true
}
return np, np.Floor(f), false
}
|