aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoop Kiefte <ikojba@gmail.com>2020-09-14 09:26:28 +0200
committerJoop Kiefte <ikojba@gmail.com>2020-09-14 09:26:56 +0200
commit007d00594170e1885b5478b3fcbedcb28d12b94e (patch)
tree7de5092d2cfb7e8c491441ceec3b8c57eb3840d6
parentd6dfb7146bc208667c57d66816195333414a038d (diff)
Add score and next, fixes #2 and #3
-rw-r--r--main.go114
-rw-r--r--tris/next.go13
2 files changed, 102 insertions, 25 deletions
diff --git a/main.go b/main.go
index 6bc8ce0..14f63a4 100644
--- a/main.go
+++ b/main.go
@@ -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
+}