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 }