perf: display optimization
This commit is contained in:
parent
3d57868e9d
commit
11781c0789
@ -1,18 +1,43 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"gol/gol"
|
||||
"gol/term"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"runtime/pprof"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
cpuprofile := flag.String("cpuprofile", "", "write cpu profile to file")
|
||||
flag.Parse()
|
||||
|
||||
// Jeśli podano flagę cpuprofile, rozpocznij profilowanie
|
||||
if *cpuprofile != "" {
|
||||
f, err := os.Create(*cpuprofile)
|
||||
if err != nil {
|
||||
log.Fatal("could not create CPU profile: ", err)
|
||||
}
|
||||
defer f.Close()
|
||||
if err := pprof.StartCPUProfile(f); err != nil {
|
||||
log.Fatal("could not start CPU profile: ", err)
|
||||
}
|
||||
defer pprof.StopCPUProfile()
|
||||
}
|
||||
game()
|
||||
}
|
||||
|
||||
func game() {
|
||||
// arenas - front one is printent, then new state is calculated into back one
|
||||
// next front and back are switched
|
||||
front := gol.New(20, 40)
|
||||
back := gol.New(20, 40)
|
||||
|
||||
// draw initial objects
|
||||
// glider
|
||||
front[0][3] = true
|
||||
front[1][4] = true
|
||||
@ -21,35 +46,40 @@ func main() {
|
||||
front[2][4] = true
|
||||
|
||||
// cross
|
||||
|
||||
front[16][21] = true
|
||||
front[17][21] = true
|
||||
front[18][21] = true
|
||||
|
||||
// catch interrupt signals
|
||||
sigs := make(chan os.Signal, 1)
|
||||
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
|
||||
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)
|
||||
|
||||
// initialize screen
|
||||
term.StartFullscreen()
|
||||
term.TurnCursor(term.CursorOff)
|
||||
|
||||
loop := func() {
|
||||
ticker := time.NewTicker(250 * time.Millisecond)
|
||||
defer ticker.Stop()
|
||||
for {
|
||||
term.GoHome()
|
||||
front.PrintMe()
|
||||
front.NextGen(back)
|
||||
front, back = back, front
|
||||
select {
|
||||
case <-sigs: // przerwanie
|
||||
return
|
||||
case <-ticker.C: // upłynął czas do kolejnej generacji
|
||||
}
|
||||
defer restoreScreen()
|
||||
|
||||
// setup timer
|
||||
ticker := time.NewTicker(250 * time.Millisecond)
|
||||
defer ticker.Stop()
|
||||
|
||||
mainLoop:
|
||||
for {
|
||||
term.GoHome()
|
||||
front.PrintMe()
|
||||
front.NextGen(back)
|
||||
front, back = back, front // switch arenas
|
||||
select {
|
||||
case <-sigs: // interrupt (Ctrl-C etc)
|
||||
break mainLoop
|
||||
case <-ticker.C: // wait for next tick
|
||||
}
|
||||
}
|
||||
defer func() {
|
||||
term.FinishFullscreen()
|
||||
term.TurnCursor(term.CursorOn)
|
||||
}()
|
||||
loop()
|
||||
}
|
||||
|
||||
// restoreScreen switch back terminal to normal mode.
|
||||
func restoreScreen() {
|
||||
term.FinishFullscreen()
|
||||
term.TurnCursor(term.CursorOn)
|
||||
}
|
||||
|
27
gol/types.go
27
gol/types.go
@ -1,6 +1,10 @@
|
||||
package gol
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type Arena [][]bool
|
||||
|
||||
@ -12,18 +16,31 @@ func New(ysize, xsize int) Arena {
|
||||
return arena
|
||||
}
|
||||
|
||||
// bufPool
|
||||
var bufPool = sync.Pool{
|
||||
New: func() any {
|
||||
return new(bytes.Buffer)
|
||||
},
|
||||
}
|
||||
|
||||
func (a Arena) PrintMe() {
|
||||
b := bufPool.Get().(*bytes.Buffer)
|
||||
b.Reset()
|
||||
spriteOn := ([]byte)("\ue0b6\ue0b4")
|
||||
spriteOff := ([]byte)("\u2022\u2022")
|
||||
|
||||
for i := 0; i < len(a); i++ {
|
||||
for j := 0; j < len(a[0]); j++ {
|
||||
if a[i][j] {
|
||||
fmt.Print("\ue0b6\ue0b4")
|
||||
b.Write(spriteOn)
|
||||
} else {
|
||||
//fmt.Print("\ue0b7\ue0b5")
|
||||
fmt.Print("\u2022\u2022")
|
||||
b.Write(spriteOff)
|
||||
}
|
||||
}
|
||||
fmt.Println()
|
||||
b.WriteRune('\n')
|
||||
}
|
||||
os.Stdout.Write(b.Bytes())
|
||||
bufPool.Put(b)
|
||||
}
|
||||
|
||||
func (a Arena) NextGen(to Arena) {
|
||||
|
23
term/term.go
23
term/term.go
@ -13,47 +13,48 @@ const (
|
||||
|
||||
// TurnCursor turns the cursor on and off according to the parameter.
|
||||
func TurnCursor(onOff CursorFlag) {
|
||||
if onOff == CursorOn {
|
||||
fmt.Printf("\033[?25h")
|
||||
} else {
|
||||
fmt.Printf("\033[?25l")
|
||||
switch onOff {
|
||||
case CursorOn:
|
||||
fmt.Print("\033[?25h")
|
||||
case CursorOff:
|
||||
fmt.Print("\033[?25l")
|
||||
}
|
||||
}
|
||||
|
||||
// ClearScreen clears current screen.
|
||||
func ClearScreen() {
|
||||
fmt.Printf("\033[2J")
|
||||
fmt.Print("\033[2J")
|
||||
}
|
||||
|
||||
// ResetTerminal resets terminal (ESC c)
|
||||
func ResetTerminal() {
|
||||
fmt.Printf("\033c")
|
||||
fmt.Print("\033c")
|
||||
}
|
||||
|
||||
// GoHome moves cursor to the home position (upper left corner)
|
||||
func GoHome() {
|
||||
fmt.Printf("\033[H")
|
||||
fmt.Print("\033[H")
|
||||
}
|
||||
|
||||
// SaveCursor saves curent position of the SaveCursor
|
||||
func SaveCursor() {
|
||||
fmt.Printf("\033[s")
|
||||
fmt.Print("\033[s")
|
||||
}
|
||||
|
||||
// RestoreCursor restore cursor to the position saved previously with SaveCursor().
|
||||
func RestoreCursor() {
|
||||
fmt.Printf("\033[u")
|
||||
fmt.Print("\033[u")
|
||||
}
|
||||
|
||||
// EnableAlternateScreen switches the terminal to the alternative screen.
|
||||
// The alternative screen doesn't have the scroll buffer.
|
||||
func EnableAlternateScreen() {
|
||||
fmt.Printf("\033[?1049h")
|
||||
fmt.Print("\033[?1049h")
|
||||
}
|
||||
|
||||
// DiableAlternateScreen switches the terminal to the primary screen.
|
||||
func DisableAlternateScreen() {
|
||||
fmt.Printf("\033[?1049l")
|
||||
fmt.Print("\033[?1049l")
|
||||
}
|
||||
|
||||
// StartFullscreen saves the cursor, enables alternate screen and clears it.
|
||||
|
Loading…
x
Reference in New Issue
Block a user