diff options
-rw-r--r-- | main.go | 28 | ||||
-rw-r--r-- | tris/core.go | 8 | ||||
-rw-r--r-- | tris/lines.go | 1 | ||||
-rw-r--r-- | tris/move.go | 4 |
4 files changed, 32 insertions, 9 deletions
@@ -22,17 +22,23 @@ func GetKey() []byte { } func main() { - rand.Seed(time.Now().UnixNano()) - var f tris.Field - var floor, topout, harddrop bool + rand.Seed(time.Now().UnixNano()) // to start with truly random pieces + var f tris.Field // the playing field (10x20) + var floor, topout, harddrop bool // state machine variables to check special situations + + // define outside of game loop to avoid accidental resets of position + // x, y and rot are the values calculated to feed to Move + // which then checks collisions and does the wall kicks var x, y int var rot tris.Rotation - var key []byte + + // init variable for pressed key - MUST be initialized 3 long to avoid crash, GetKey() does this + key := GetKey() + fmt.Print("\033[2J") // Clear screen b := tris.NewBag() b, p := b.Pick() t := time.Tick(time.Second) - key = GetKey() for { x, y, rot = p.X, p.Y, p.Rot if !harddrop { @@ -76,19 +82,23 @@ func main() { y = p.Y + 1 } } - p, floor, topout = p.Move(f, rot, x, y) + p, floor, topout = p.Move(f, rot, x, y) // Check if the piece can move, then do it and communicate back for housekeeping + + // Give some time before actually locking in to enable tucks + // This code runs when the time is over if floor && p.Lock.Add(tris.LockDelay).Before(time.Now()) { harddrop = false var l int f = f.Add(p) - l, f = f.Lines() + l, f = f.Lines() // count and remove full lines if l > 0 { - fmt.Println(l, " lines removed!") + fmt.Println(l, "lines removed!") time.Sleep(time.Second) } fmt.Print("\033[2J") // Clear screen - b, p = b.Pick() + b, p = b.Pick() // ... and pick a new piece from the bag } + // when not touching a piece or floor below yet, reset lock delay if !floor { p.Lock = time.Now() } diff --git a/tris/core.go b/tris/core.go index 8a9c16b..087203e 100644 --- a/tris/core.go +++ b/tris/core.go @@ -38,6 +38,8 @@ const ( CounterClockwise ) +// a placement is the combination of a piece and where it exactly is on the board +// we use this both for the actual piece and for checking hypothetical positions type Placement struct { piece Piece X int @@ -46,6 +48,7 @@ type Placement struct { Lock time.Time } +// Collide checks if any squares of the Placement and the Field overlap func (p Placement) Collide(f Field) bool { pf, ok := p.Field() for x := 0; x < 10; x++ { @@ -58,6 +61,8 @@ func (p Placement) Collide(f Field) bool { return !ok } +// Field translates the Placement into a Field format +// When it gets out of the board, we return that to the caller with a bool func (p Placement) Field() (Field, bool) { var f Field ok := true @@ -74,6 +79,7 @@ func (p Placement) Field() (Field, bool) { return f, ok } +// Points transforms the piece to a list of coordinates func (p Placement) Points() []Point { piece := p.piece[p.Rot] var points []Point @@ -114,6 +120,7 @@ func (b Bag) Pick() (Bag, Placement) { type Field [20][10]bool +// Add merges the Field and Piece together func (f Field) Add(p Placement) Field { fn := f for _, point := range p.Points() { @@ -126,6 +133,7 @@ func (f Field) Add(p Placement) Field { } +// The command line tool uses this representation as the actual playing field func (f Field) String() (output string) { for _, row := range f { for _, block := range row { diff --git a/tris/lines.go b/tris/lines.go index 5cb6981..7c7026b 100644 --- a/tris/lines.go +++ b/tris/lines.go @@ -1,5 +1,6 @@ package tris +// Lines counts the number of lines that is completed and returns a Field with them removed func (f Field) Lines() (int, Field) { full := [10]bool{true, true, true, true, true, true, true, true, true, true} empty := [10]bool{false, false, false, false, false, false, false, false, false, false} diff --git a/tris/move.go b/tris/move.go index 127ce06..c5ba1ef 100644 --- a/tris/move.go +++ b/tris/move.go @@ -3,6 +3,7 @@ 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}}, @@ -10,6 +11,7 @@ var K3CW = Kicks{ 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}}, @@ -17,6 +19,7 @@ var LCW = Kicks{ 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 @@ -38,6 +41,7 @@ func (ks Kicks) Try(rot Rotation, reverse bool, p Placement, f Field) (np Placem return p } +// Floor checks if the piece touches something underneath it func (p Placement) Floor(f Field) bool { fp := p fp.Y++ |