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 }