Skip to content

Commit 7d50a86

Browse files
committed
Make debug renderer more effecient
1 parent e2257d6 commit 7d50a86

File tree

5 files changed

+107
-45
lines changed

5 files changed

+107
-45
lines changed

Diff for: gopher-maze-2/cmd/maze/main.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import (
1010
func main() {
1111
ctx := context.Background()
1212

13-
g := game.New(true)
13+
g := game.New()
1414

1515
// Start rendering loop
1616
go g.Loop(ctx)

Diff for: gopher-maze-2/internal/developer/developer.go

+45-15
Original file line numberDiff line numberDiff line change
@@ -3,35 +3,43 @@ package developer
33

44
import (
55
"fmt"
6-
"log"
76
"time"
87
)
98

9+
type Stack interface {
10+
Add(string)
11+
Addf(string, ...string)
12+
Get(int) string
13+
Window() []string
14+
}
15+
1016
// DebugStack implements a stack of debugging messages that can be rendered via
1117
// a sliding window to the terminal. Should be instantiated via NewDebugStack()
1218
type DebugStack struct {
13-
size uint8
14-
msgs []string
19+
clean bool
20+
size uint8
21+
msgs []string
22+
lastWindow []string
1523
}
1624

1725
// NewDebugStack initialises an empty debug stack with its
1826
// window set to the size of `windowSize`.
19-
func NewDebugStack(enable bool, windowSize uint8) *DebugStack {
27+
func NewDebugStack(windowSize uint8) *DebugStack {
2028
return &DebugStack{
21-
size: windowSize,
22-
msgs: make([]string, windowSize),
29+
clean: false,
30+
size: windowSize,
31+
msgs: make([]string, windowSize),
32+
lastWindow: make([]string, windowSize),
2333
}
2434
}
2535

26-
// Add appends a new message to the debug stack. The message is also echoed to
27-
// the STDOUT log.
36+
// Add appends a new message to the debug stack.
2837
func (ds *DebugStack) Add(msg string) {
2938
ds.msgs = append(ds.msgs, fmt.Sprintf("[%s] %s", time.Now().Format("15:04:05"), msg))
30-
log.Println(msg)
39+
ds.clean = false
3140
}
3241

33-
// Add appends a new message to the debug stack (formatted). The message is
34-
// also echoed to the STDOUT log.
42+
// Add appends a new message to the debug stack (formatted).
3543
func (ds *DebugStack) Addf(format string, msg ...string) {
3644
ds.Add(fmt.Sprintf(format, msg))
3745
}
@@ -40,14 +48,36 @@ func (ds *DebugStack) Addf(format string, msg ...string) {
4048
// (if it exists). If the index isn't populated or is out
4149
// of range then an empty string is returned instead.
4250
func (ds *DebugStack) Get(i int) string {
51+
window := ds.lastWindow
52+
if !ds.clean {
53+
// If the debug stack has changed
54+
// then rebuild the window.
55+
window = ds.Window()
56+
}
57+
if i >= len(window) {
58+
return ""
59+
}
60+
return window[i]
61+
}
62+
63+
// Window returns a whole debug window
64+
func (ds *DebugStack) Window() []string {
4365
upper := len(ds.msgs)
4466
lower := upper - int(ds.size)
4567
if lower < 0 {
4668
lower = 0
4769
}
4870
window := ds.msgs[lower:upper]
49-
if i >= len(window) {
50-
return ""
51-
}
52-
return window[i]
71+
ds.clean = true
72+
ds.lastWindow = window
73+
return window
5374
}
75+
76+
// NullStack is used when we want to disable debugging stacks. It essentially
77+
// returns no-ops for every func.
78+
type NullStack struct{}
79+
80+
func (*NullStack) Add(string) {}
81+
func (*NullStack) Addf(string, ...string) {}
82+
func (*NullStack) Get(int) string { return "" }
83+
func (*NullStack) Window() []string { return nil }

Diff for: gopher-maze-2/internal/developer/developer_test.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ func TestDebugStack(t *testing.T) {
1414
stackSize := uint8(3)
1515

1616
t.Run("Create a new debug stack", func(t *testing.T) {
17-
ds = developer.NewDebugStack(true, stackSize)
17+
ds = developer.NewDebugStack(stackSize)
1818
assert.NotNil(t, ds)
1919
})
2020

@@ -46,12 +46,12 @@ func TestDebugStack(t *testing.T) {
4646
})
4747

4848
t.Run("Attempt fetch on empty stack", func(t *testing.T) {
49-
ds = developer.NewDebugStack(true, stackSize)
49+
ds = developer.NewDebugStack(stackSize)
5050
assert.Equal(t, ds.Get(0), "")
5151
})
5252

5353
t.Run("Attempt fetch on disbled stack", func(t *testing.T) {
54-
ds = developer.NewDebugStack(false, stackSize)
54+
ds = developer.NewDebugStack(stackSize)
5555
assert.Equal(t, ds.Get(0), "")
5656
})
5757

Diff for: gopher-maze-2/internal/game/game.go

+10-6
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,16 @@ import (
1111
"github.com/necrophonic/3d-gopher-maze/gopher-maze-2/internal/terminal"
1212
)
1313

14-
var ds *developer.DebugStack
14+
var ds developer.Stack
1515

1616
func init() {
17-
// TODO make debug switchable via env vars
18-
ds = developer.NewDebugStack(true, 11)
19-
ds.Add("[debug enabled]")
17+
debug := os.Getenv("DEBUG")
18+
if debug == "true" {
19+
ds = developer.NewDebugStack(11)
20+
ds.Add("[debug enabled]")
21+
} else {
22+
ds = &developer.NullStack{}
23+
}
2024
}
2125

2226
type (
@@ -37,9 +41,9 @@ type (
3741
)
3842

3943
// New initialises a new game with defaults
40-
func New(debug bool) *Game {
44+
func New() *Game {
4145
return &Game{
42-
Tick: 100_000 * time.Microsecond,
46+
Tick: 100 * time.Millisecond,
4347
Player: NewPlayer(),
4448
}
4549
}

Diff for: gopher-maze-2/internal/game/render.go

+48-20
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,63 @@
11
package game
22

33
import (
4-
"strings"
4+
"bytes"
5+
"text/template"
56
)
67

7-
const (
8-
windowHoriz = "═"
9-
windowTopLeft = "╔"
10-
windowTopRight = "╗"
11-
windowBottomLeft = "╚"
12-
windowBottomRight = "╝"
13-
windowSide = "║"
14-
)
8+
// const (
9+
// windowHoriz = "═"
10+
// windowTopLeft = "╔"
11+
// windowTopRight = "╗"
12+
// windowBottomLeft = "╚"
13+
// windowBottomRight = "╝"
14+
// windowSide = "║"
15+
// )
1516

16-
const (
17-
windowWidth = 22
18-
windowHeight = 9
19-
)
17+
// const (
18+
// windowWidth = 22
19+
// windowHeight = 9
20+
// )
2021

2122
// Render contructs the terminal view. If debug is enabled, the debug stack
2223
// is rendered alongside the viewport.
2324
func (g *Game) Render() (string, error) {
2425
// Build the output
25-
rendered := ""
26+
// rendered := ""
27+
28+
// rendered += windowTopLeft + strings.Repeat(windowHoriz, windowWidth+2) + windowTopRight + " " + ds.Get(0) + "\n"
29+
// for i := 0; i < windowHeight; i++ {
30+
// // TODO - content!
31+
// rendered += windowSide + " " + strings.Repeat(" ", windowWidth) + " " + windowSide + " " + ds.Get(i+1) + "\n"
32+
// }
33+
// rendered += windowBottomLeft + strings.Repeat(windowHoriz, windowWidth+2) + windowBottomRight + " " + ds.Get(windowHeight+1) + "\n"
34+
35+
buf := &bytes.Buffer{}
2636

27-
rendered += windowTopLeft + strings.Repeat(windowHoriz, windowWidth+2) + windowTopRight + " " + ds.Get(0) + "\n"
28-
for i := 0; i < windowHeight; i++ {
29-
// TODO - content!
30-
rendered += windowSide + " " + strings.Repeat(" ", windowWidth) + " " + windowSide + " " + ds.Get(i+1) + "\n"
37+
err := tmplScreen11_9.Execute(buf, nil)
38+
if err != nil {
39+
return "", err
3140
}
32-
rendered += windowBottomLeft + strings.Repeat(windowHoriz, windowWidth+2) + windowBottomRight + " " + ds.Get(windowHeight+1) + "\n"
3341

34-
return rendered, nil
42+
return buf.String(), nil
3543
}
44+
45+
var funcs = template.FuncMap{
46+
"getDebugLine": func(i int) string {
47+
return ds.Get(i)
48+
},
49+
}
50+
51+
var tmplScreen11_9 = template.Must(template.New("screen").Funcs(funcs).Parse(`
52+
╔════════════════════════╗ {{ getDebugLine 0 }}
53+
║ ║ {{ getDebugLine 1 }}
54+
║ ║ {{ getDebugLine 2 }}
55+
║ ║ {{ getDebugLine 3 }}
56+
║ ║ {{ getDebugLine 4 }}
57+
║ ║ {{ getDebugLine 5 }}
58+
║ ║ {{ getDebugLine 6 }}
59+
║ ║ {{ getDebugLine 7 }}
60+
║ ║ {{ getDebugLine 8 }}
61+
║ ║ {{ getDebugLine 9 }}
62+
╚════════════════════════╝ {{ getDebugLine 10 }}
63+
`))

0 commit comments

Comments
 (0)