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
|
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(p, np Placement, f Field) Placement {
direction := (np.Rot - p.Rot + 4) % 4
rot := np.Rot
factor := 1
if direction == Spawn {
factor = 0
}
if direction == CounterClockwise {
rot = (rot + 1) % 4
factor = -1
}
x, y := np.X, np.Y
for _, k := range ks[rot] {
np.X, np.Y = x + k.X * factor, y + k.Y * factor
if !np.Collide(f) {
return np
}
}
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)
}
// 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(p, np, f)
case JPiece, SPiece, ZPiece, TPiece, LPiece:
np = K3CW.Try(p, np, f)
default:
np = p
}
if np.Floor(f) && np.Y < 0 {
return np, true, true
}
return np, np.Floor(f), false
}
|