diff options
author | Joop Kiefte <ikojba@gmail.com> | 2020-09-14 09:26:28 +0200 |
---|---|---|
committer | Joop Kiefte <ikojba@gmail.com> | 2020-09-14 09:26:56 +0200 |
commit | 007d00594170e1885b5478b3fcbedcb28d12b94e (patch) | |
tree | 7de5092d2cfb7e8c491441ceec3b8c57eb3840d6 | |
parent | d6dfb7146bc208667c57d66816195333414a038d (diff) |
Add score and next, fixes #2 and #3
-rw-r--r-- | main.go | 114 | ||||
-rw-r--r-- | tris/next.go | 13 |
2 files changed, 102 insertions, 25 deletions
@@ -4,26 +4,66 @@ import ( "fmt" "git.kiefte.eu/lapingvino/clitris/tris" "github.com/pkg/term" - "time" "math/rand" + "time" ) +func pos(l, c int) { + fmt.Printf("\033[%d;%dH", l, c) +} + +func ppos(l, c int, s string) { + pos(l, c) + fmt.Print(s) +} + +func fpos(l, c int, f tris.Field) { + pos(l, c) + for i, r := range f { + ppos(l+i, c, render(r, "\u2588\u2589", "\u2591\u2591")+"|") + } +} + +func npos(l, c int, f tris.Field) { + pos(l, c) + for i, r := range f { + ppos(l+i, c, render(r, "\u2588\u2589", " ")) + } +} + +func render(r [10]bool, block, empty string) string { + var s string + for _, c := range r { + if c { + s += block + } else { + s += empty + } + } + return s +} + // GetKey() returns the key currently pressed. It always returns a 3 byte slice. Check first element for Escape for handling arrow keys // Because a defer would trigger too late and the Restore and Close are essential, separated in a function. -func GetKey() []byte { - t, _ := term.Open("/dev/tty") - term.RawMode(t) +func GetKey(t *term.Term) []byte { key := make([]byte, 3) - t.SetReadTimeout(time.Second / 1000) t.Read(key) - t.Restore() - t.Close() return key } func main() { + t, _ := term.Open("/dev/tty") + defer t.Close() + + term.RawMode(t) + defer t.Restore() + defer ppos(0, 0, "\033[2J") // Clear screen and back to 0,0 + + t.SetReadTimeout(time.Second / 1000) + rand.Seed(time.Now().UnixNano()) // to start with truly random pieces - var f tris.Field // the playing field (10x20) + + 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 @@ -32,51 +72,71 @@ func main() { var x, y int var rot tris.Rotation + var level, linescleared, score, dropfrom int + // init variable for pressed key - MUST be initialized 3 long to avoid crash, GetKey() does this - key := GetKey() + key := GetKey(t) fmt.Print("\033[2J") // Clear screen b := tris.NewBag() b, p := b.Pick() - t := time.Tick(time.Second) + lev := time.NewTicker(time.Second) + level = 1 for { x, y, rot = p.X, p.Y, p.Rot + level = linescleared/10 + 1 + slevel := fmt.Sprintf("level %d", level) + sscore := fmt.Sprintf("score %d", score) + slines := fmt.Sprintf("lines %d", linescleared) if !harddrop { - fmt.Print("\033[0;0H") // Position to 0,0 - fmt.Println(f.Add(p).String()) - key = GetKey() + fpos(0, 0, f.Add(p)) + var next tris.Field + b, next = b.Next(5) + npos(0, 24, next) + ppos(1, 32, sscore) + ppos(3, 32, slevel) + ppos(5, 32, slines) + key = GetKey(t) } switch key[0] { case 27: // Escape, read the arrow key pressed switch key[2] { case 65: // Up - rot = (p.Rot + 1)%4 + rot = (p.Rot + 1) % 4 case 66: // Down y = p.Y + 1 + score += 1 case 67: // Right x = p.X + 1 case 68: // Left x = p.X - 1 default: - fmt.Println("...escape, escape!") + ppos(22, 0, "...escape, escape!") + time.Sleep(2 * time.Second) return } case 'x': - rot = (p.Rot + 1)%4 + rot = (p.Rot + 1) % 4 case 'z': - rot = (p.Rot + 3)%4 + rot = (p.Rot + 3) % 4 case ' ': + if !harddrop { + dropfrom = p.Y + } harddrop = true case 'q': - fmt.Println("...that was exciting!") + ppos(22, 0, "...that was exciting!") + time.Sleep(2 * time.Second) return case 'Q': - fmt.Println("...never let an engineer pick the name of your software?") + ppos(22, 0, "...never let an engineer pick the name of your software?") + time.Sleep(2 * time.Second) return } select { - case <-t: + case <-lev.C: y = p.Y + 1 + lev.Reset(time.Second * 100 / (100 * time.Duration(level))) default: if harddrop { y = p.Y + 1 @@ -87,16 +147,19 @@ func main() { // 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 + if harddrop { + score += 2 * (p.Y - dropfrom) + harddrop = false + } var l int f = f.Add(p) l, f = f.Lines() // count and remove full lines if l > 0 { - fmt.Println(l, "lines removed!") - time.Sleep(time.Second) + linescleared += l + score += level * l * l } fmt.Print("\033[2J") // Clear screen - b, p = b.Pick() // ... and pick a new piece from the bag + 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 { @@ -104,7 +167,8 @@ func main() { } if topout { - fmt.Println("GAME OVER") + ppos(4, 5, " GAME OVER ") + time.Sleep(2 * time.Second) return } } diff --git a/tris/next.go b/tris/next.go new file mode 100644 index 0000000..e72a4ff --- /dev/null +++ b/tris/next.go @@ -0,0 +1,13 @@ +package tris + +func (b Bag) Next(n int) (Bag, Field) { + var f Field + for len(b) < n { + b = append(b, NewBag()...) + } + nextpieces := b[:n] + for i, p := range nextpieces { + f = f.Add(Placement{piece: p, Y:2+i*4}) + } + return b, f +} |