Optimize matrix data model

This commit is contained in:
Trevor Slocum 2019-10-28 16:25:07 -07:00
parent e6a3c0527c
commit f853512332
10 changed files with 111 additions and 143 deletions

View file

@ -273,9 +273,11 @@ func renderPlayerGUI() {
player.Preview.Clear()
err := player.Preview.Add(p, p.Solid, mino.Point{0, 0}, false)
if err != nil {
log.Fatalf("failed to render preview matrix: %+v", err)
if !player.Matrix.GameOver {
err := player.Preview.Add(p, p.Solid, mino.Point{0, 0}, false)
if err != nil {
log.Fatalf("failed to render preview matrix: failed to add ghost piece: %+v", err)
}
}
m.Lock()
@ -453,9 +455,9 @@ func renderMatrixes(mx []*mino.Matrix) {
for x := 0; x < m.W; x++ {
renderBuffer.WriteRune('[')
renderBuffer.Write(m.Block(x, y-1).Color())
renderBuffer.Write(mino.Colors[m.Block(x, y-1)])
renderBuffer.WriteRune(':')
renderBuffer.Write(m.Block(x, y).Color())
renderBuffer.Write(mino.Colors[m.Block(x, y)])
renderBuffer.WriteRune(']')
renderBuffer.WriteRune('▄')
renderBuffer.Write([]byte("[-:-]"))
@ -466,7 +468,7 @@ func renderMatrixes(mx []*mino.Matrix) {
}
}
if y != 0 || mt != mino.MatrixCustom {
if y > 1 || mt != mino.MatrixCustom {
renderBuffer.WriteRune('\n')
}
}
@ -488,7 +490,7 @@ func renderMatrixes(mx []*mino.Matrix) {
for x := 0; x < m.W; x++ {
renderBuffer.WriteRune('[')
renderBuffer.Write(m.Block(x, y).Color())
renderBuffer.Write(mino.Colors[m.Block(x, y)])
renderBuffer.WriteRune(']')
renderBuffer.WriteRune('█')
renderBuffer.WriteRune('█')
@ -525,7 +527,7 @@ func renderMatrixes(mx []*mino.Matrix) {
for x := 0; x < m.W; x++ {
renderBuffer.WriteRune('[')
renderBuffer.Write(m.Block(x, y).Color())
renderBuffer.Write(mino.Colors[m.Block(x, y)])
renderBuffer.WriteRune(']')
renderBuffer.WriteRune('█')
renderBuffer.WriteRune('█')

View file

@ -88,10 +88,17 @@ func initGUI(skipTitle bool) (*tview.Application, error) {
piece *mino.Piece
addToRight bool
i int
offset int
)
for y := 0; y < 11; y++ {
for x := 0; x < 4; x++ {
piece = mino.NewPiece(minos[i], mino.Point{(x * 5) + 2, (y * 5)})
if !addToRight {
offset = 3
} else {
offset = 2
}
piece = mino.NewPiece(minos[i], mino.Point{(x * 5) + offset, (y * 5)})
i++
if i == len(minos) {
@ -137,22 +144,23 @@ func initGUI(skipTitle bool) (*tview.Application, error) {
buttonC = tview.NewButton("C")
buttonLabelC = tview.NewTextView().SetTextAlign(tview.AlignCenter)
titleNameGrid := tview.NewGrid().SetRows(3).
titleNameGrid := tview.NewGrid().SetRows(3, 2).
AddItem(titleName, 0, 0, 1, 1, 0, 0, false).
AddItem(tview.NewTextView().SetText(SubTitle+game.Version), 1, 0, 1, 1, 0, 0, false)
titleGrid = tview.NewGrid().
SetRows(5, 3, 3, 3, 3, 3, 4).
SetRows(5, 3, 3, 3, 3, 3, 3).
SetColumns(-1, 34, -1).
AddItem(titleL, 0, 0, 7, 1, 0, 0, false).
AddItem(titleL, 0, 0, 8, 1, 0, 0, false).
AddItem(titleNameGrid, 0, 1, 1, 1, 0, 0, false).
AddItem(titleR, 0, 2, 7, 1, 0, 0, false).
AddItem(titleR, 0, 2, 8, 1, 0, 0, false).
AddItem(buttonA, 1, 1, 1, 1, 0, 0, false).
AddItem(buttonLabelA, 2, 1, 1, 1, 0, 0, false).
AddItem(buttonB, 3, 1, 1, 1, 0, 0, false).
AddItem(buttonLabelB, 4, 1, 1, 1, 0, 0, false).
AddItem(buttonC, 5, 1, 1, 1, 0, 0, false).
AddItem(buttonLabelC, 6, 1, 1, 1, 0, 0, false)
AddItem(buttonLabelC, 6, 1, 1, 1, 0, 0, false).
AddItem(pad, 7, 1, 1, 1, 0, 0, false)
gameListView = tview.NewTextView().SetDynamicColors(true)
@ -167,7 +175,7 @@ func initGUI(skipTitle bool) (*tview.Application, error) {
gameListHeader = tview.NewTextView().SetTextAlign(tview.AlignCenter)
gameListGrid = tview.NewGrid().
SetRows(5, 1, -1, 1, 3).
SetRows(5, 1, 14, 1, 3).
SetColumns(-1, 34, -1).
AddItem(titleL, 0, 0, 5, 1, 0, 0, false).
AddItem(titleNameGrid, 0, 1, 1, 1, 0, 0, false).
@ -412,7 +420,7 @@ func newTitleMatrixName() *mino.Matrix {
}
}()
m := mino.NewMatrix(36, 5, 0, 1, ev, draw, mino.MatrixCustom)
m := mino.NewMatrix(36, 6, 0, 1, ev, draw, mino.MatrixCustom)
centerStart := (m.W / 2) - 17

View file

@ -19,7 +19,9 @@ func TestRenderMatrix(t *testing.T) {
m.AddTestBlocks()
renderPlayerMatrix(m)
mx := []*mino.Matrix{m}
renderMatrixes(mx)
}
func BenchmarkRenderStandardMatrix(b *testing.B) {
@ -35,11 +37,13 @@ func BenchmarkRenderStandardMatrix(b *testing.B) {
m.AddTestBlocks()
mx := []*mino.Matrix{m}
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
renderPlayerMatrix(m)
renderMatrixes(mx)
}
}
@ -56,11 +60,13 @@ func BenchmarkRenderLargeMatrix(b *testing.B) {
m.AddTestBlocks()
mx := []*mino.Matrix{m}
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
renderPlayerMatrix(m)
renderMatrixes(mx)
}
blockSize = 1

View file

@ -338,7 +338,7 @@ func renderGameList() {
gameListView.Write(renderRTee)
gameListView.Write([]byte("\n"))
h := 9
h := 10
for i, g := range gameList {
p := strconv.Itoa(g.Players)

View file

@ -340,10 +340,7 @@ func (s *Server) handleGameCommands(pl *Player, g *Game) {
switch p := e.(type) {
case *GameCommandDisconnect:
log.Printf("%+v", g.Players)
if _, ok := g.Players[p.SourcePlayer]; ok {
g.RemovePlayerL(p.SourcePlayer)
}
g.RemovePlayerL(p.SourcePlayer)
case *GameCommandMessage:
if player, ok := g.Players[p.SourcePlayer]; ok {
s.Logf("<%s> %s", player.Name, p.Message)

View file

@ -22,8 +22,8 @@ func TestBag(t *testing.T) {
b, err := NewBag(0, minos, 10)
if err != nil {
t.Errorf("failed to create bag for rank %d: %s", d.Rank, err)
}
taken := make(map[string]int)
for i := 1; i < 4; i++ {
for i := 0; i < len(d.Minos); i++ {

View file

@ -1,5 +1,26 @@
package mino
// Dark color ghosts are 60% original overlaid #777777
// Light color ghosts are 40% original overlaid #888888
var Colors = [][]byte{
BlockNone: []byte("#000000"),
BlockGarbage: []byte("#999999"),
BlockGhostBlue: []byte("#6e7bc3"),
BlockGhostCyan: []byte("#6bbaba"),
BlockGhostRed: []byte("#ba6b6b"),
BlockGhostYellow: []byte("#b1b16b"),
BlockGhostMagenta: []byte("#a16ba8"),
BlockGhostGreen: []byte("#6bb76b"),
BlockGhostOrange: []byte("#c3806c"),
BlockSolidBlue: []byte("#2864ff"),
BlockSolidCyan: []byte("#00eeee"),
BlockSolidRed: []byte("#ee0000"),
BlockSolidYellow: []byte("#dddd00"),
BlockSolidMagenta: []byte("#c000cc"),
BlockSolidGreen: []byte("#00e900"),
BlockSolidOrange: []byte("#ff7308"),
}
type Block int
func (b Block) String() string {
@ -19,48 +40,6 @@ func (b Block) Rune() rune {
}
}
func (b Block) Color() []byte {
// Dark color ghosts are 60% original overlaid #777777
// Light color ghosts are 40% original overlaid #888888
switch b {
case BlockNone:
return []byte("#000000")
case BlockGhostBlue:
return []byte("#6e7bc3")
case BlockSolidBlue:
return []byte("#2864ff")
case BlockGhostCyan:
return []byte("#6bbaba")
case BlockSolidCyan:
return []byte("#00eeee")
case BlockGhostRed:
return []byte("#ba6b6b")
case BlockSolidRed:
return []byte("#ee0000")
case BlockGhostYellow:
return []byte("#b1b16b")
case BlockSolidYellow:
return []byte("#dddd00")
case BlockGhostMagenta:
return []byte("#a16ba8")
case BlockSolidMagenta:
return []byte("#c000cc")
case BlockGhostGreen:
return []byte("#6bb76b")
case BlockSolidGreen:
return []byte("#00e900")
case BlockGhostOrange:
return []byte("#c3806c")
case BlockSolidOrange:
return []byte("#ff7308")
case BlockGarbage:
return []byte("#999999")
default:
return []byte("#ffffff")
}
}
const (
BlockNone Block = iota
BlockGarbage

View file

@ -30,8 +30,8 @@ type Matrix struct {
H int `json:"-"` // Height
B int `json:"-"` // Buffer height
M map[int]Block // Matrix
O map[int]Block `json:"-"` // Overlay
M []Block // Matrix
O []Block `json:"-"` // Overlay
Bag *Bag `json:"-"`
P *Piece
@ -66,9 +66,17 @@ func I(x int, y int, w int) int {
}
func NewMatrix(w int, h int, b int, players int, event chan<- interface{}, draw chan event.DrawObject, t MatrixType) *Matrix {
m := Matrix{W: w, H: h, B: b, M: make(map[int]Block), O: make(map[int]Block), Event: event, draw: draw, Type: t}
m.Move = make(chan int, 10)
m := Matrix{
Type: t,
W: w,
H: h,
B: b,
M: make([]Block, w*(h+b)),
O: make([]Block, w*(h+b)),
Event: event,
Move: make(chan int, 10),
draw: draw,
}
return &m
}
@ -212,7 +220,7 @@ func (m *Matrix) add(mn *Piece, b Block, loc Point, overlay bool) error {
x, y int
index int
M map[int]Block
M []Block
)
if overlay {
@ -368,8 +376,8 @@ func (m *Matrix) ClearOverlay() {
}
func (m *Matrix) clearOverlay() {
for i := range m.O {
if m.O[i] == BlockNone {
for i, b := range m.O {
if b == BlockNone {
continue
}
@ -396,8 +404,8 @@ func (m *Matrix) Clear() {
m.Lock()
defer m.Unlock()
for i := range m.M {
if m.M[i] == BlockNone {
for i, b := range m.M {
if b == BlockNone {
continue
}
@ -447,29 +455,15 @@ func (m *Matrix) DrawPiecesL() {
}
}
func (m *Matrix) NewM() map[int]Block {
newM := make(map[int]Block, len(m.M))
for i, b := range m.M {
newM[i] = b
}
return newM
}
func (m *Matrix) NewO() map[int]Block {
newO := make(map[int]Block, len(m.O))
for i, b := range m.O {
newO[i] = b
}
return newO
}
func (m *Matrix) Block(x int, y int) Block {
index := I(x, y, m.W)
if index < 0 || index > m.W*(m.H+m.B) {
return BlockGarbage
}
// Return overlay block first
if b, ok := m.O[index]; ok && b != BlockNone {
b := m.O[index]
if b != BlockNone {
return b
}
@ -519,13 +513,13 @@ func (m *Matrix) SetBlock(x int, y int, block Block, overlay bool) bool {
index := I(x, y, m.W)
if overlay {
if b, ok := m.O[index]; ok && b != BlockNone {
if m.O[index] != BlockNone {
return false
}
m.O[index] = block
} else {
if b, ok := m.M[index]; ok && b != BlockNone {
if m.M[index] != BlockNone {
return false
}

View file

@ -59,21 +59,20 @@ func (m Mino) Equal(other Mino) bool {
}
func (m Mino) String() string {
newMino := make(Mino, len(m))
copy(newMino, m)
sort.Sort(newMino)
sort.Sort(m)
var b strings.Builder
for i := range newMino {
b.Grow(5*len(m) + (len(m) - 1))
for i := range m {
if i > 0 {
b.WriteRune(',')
}
b.WriteRune('(')
b.WriteString(strconv.Itoa(newMino[i].X))
b.WriteString(strconv.Itoa(m[i].X))
b.WriteRune(',')
b.WriteString(strconv.Itoa(newMino[i].Y))
b.WriteString(strconv.Itoa(m[i].Y))
b.WriteRune(')')
}

View file

@ -20,58 +20,41 @@ type RotationOffsets []Point
type PieceType int
const (
PieceI PieceType = iota
PieceUnknown PieceType = iota
PieceI
PieceO
PieceJ
PieceL
PieceS
PieceT
PieceZ
PieceJLSTZ
)
var AllRotationPivotsCW = map[PieceType][]Point{
PieceI: {{1, -2}, {-1, 0}, {1, -1}, {0, 0}},
PieceO: {{1, 0}, {1, 0}, {1, 0}, {1, 0}},
PieceJ: {{1, -1}, {0, 0}, {1, 0}, {1, 0}},
PieceL: {{1, -1}, {0, 0}, {1, 0}, {1, 0}},
PieceS: {{1, -1}, {0, 0}, {1, 0}, {1, 0}},
PieceT: {{1, -1}, {0, 0}, {1, 0}, {1, 0}},
PieceZ: {{1, -1}, {0, 0}, {1, 0}, {1, 0}},
var AllRotationPivotsCW = [][]Point{
PieceUnknown: {{0, 0}, {0, 0}, {0, 0}, {0, 0}},
PieceI: {{1, -2}, {-1, 0}, {1, -1}, {0, 0}},
PieceO: {{1, 0}, {1, 0}, {1, 0}, {1, 0}},
PieceJ: {{1, -1}, {0, 0}, {1, 0}, {1, 0}},
PieceL: {{1, -1}, {0, 0}, {1, 0}, {1, 0}},
PieceS: {{1, -1}, {0, 0}, {1, 0}, {1, 0}},
PieceT: {{1, -1}, {0, 0}, {1, 0}, {1, 0}},
PieceZ: {{1, -1}, {0, 0}, {1, 0}, {1, 0}},
}
// IN PROGRESS
var AllRotationPivotsCCW = map[PieceType][]Point{
PieceI: {{2, 1}, {-1, 00}, {2, 2}, {1, 3}},
PieceO: {{0, 1}, {0, 1}, {0, 1}, {0, 1}},
PieceJ: {{1, 1}, {0, 0}, {1, 2}, {1, 2}},
PieceL: {{1, 1}, {0, 0}, {1, 2}, {1, 2}},
PieceS: {{1, 1}, {0, 0}, {1, 2}, {1, 2}},
PieceT: {{1, 1}, {0, 2}, {1, 2}, {1, 2}},
PieceZ: {{1, 1}, {0, 0}, {1, 2}, {1, 2}},
var AllRotationPivotsCCW = [][]Point{
PieceUnknown: {{0, 0}, {0, 0}, {0, 0}, {0, 0}},
PieceI: {{2, 1}, {-1, 00}, {2, 2}, {1, 3}},
PieceO: {{0, 1}, {0, 1}, {0, 1}, {0, 1}},
PieceJ: {{1, 1}, {0, 0}, {1, 2}, {1, 2}},
PieceL: {{1, 1}, {0, 0}, {1, 2}, {1, 2}},
PieceS: {{1, 1}, {0, 0}, {1, 2}, {1, 2}},
PieceT: {{1, 1}, {0, 2}, {1, 2}, {1, 2}},
PieceZ: {{1, 1}, {0, 0}, {1, 2}, {1, 2}},
}
// AllRotationOffets is a list of all piece offsets. Each set includes offsets
// for 0, R, L and 2 rotation states.
// Rotation offsets
var AllOffsets = []Point{{0, 0}, {-1, 0}, {1, 0}, {0, -1}, {-1, -1}, {1, -1}, {-2, 0}, {2, 0}}
/*
var AllRotationOffsets = map[PieceType][]RotationOffsets{
PieceI: {
{{0, 0}, {-1, 0}, {-1, 1}, {0, 1}},
{{-1, 0}, {0, 0}, {1, 1}, {0, 1}},
{{2, 0}, {0, 0}, {-2, 1}, {0, 1}},
{{-1, 0}, {0, 1}, {1, 0}, {0, -1}},
{{2, 0}, {0, -2}, {-2, 0}, {0, 2}}},
PieceO: {{{0, 0}, {0, -1}, {-1, -1}, {-1, 0}}},
PieceJLSTZ: {
{{0, 0}, {0, 0}, {0, 0}, {0, 0}},
{{0, 0}, {1, 0}, {0, 0}, {-1, 0}},
{{0, 0}, {1, -1}, {0, 0}, {-1, -1}},
{{0, 0}, {0, 2}, {0, 0}, {0, 2}},
{{0, 0}, {1, 2}, {0, 0}, {-1, 2}}}}
*/
type Piece struct {
Point `json:"pp,omitempty"`
Mino `json:"pm,omitempty"`