From e9ec8cd1dd2b4ed306079be8b410106fb2706625 Mon Sep 17 00:00:00 2001 From: MichaelS11 Date: Wed, 14 Feb 2018 12:57:02 -0800 Subject: [PATCH] Added boards, including a heart :) Improved AI slightly --- README.md | 21 +- ai.go | 173 ++---- ai_test.go | 739 +++++++++--------------- board.go | 159 ++++- boards.go | 1086 +++++++++++++++++++++++++++++++++++ boards_test.go | 30 + engine.go | 64 +-- globals.go | 103 ++++ keyInput.go | 30 +- mino.go | 81 +-- mino_test.go | 120 ++++ minos.go | 29 +- ranking.go | 17 +- screenshots/screenshot3.png | Bin 6134 -> 8040 bytes screenshots/screenshot4.png | Bin 0 -> 6970 bytes tetris.go | 26 +- view.go | 146 +++-- 17 files changed, 2038 insertions(+), 786 deletions(-) create mode 100644 boards.go create mode 100644 boards_test.go create mode 100644 globals.go create mode 100644 mino_test.go create mode 100644 screenshots/screenshot4.png diff --git a/README.md b/README.md index cea1b41..f18526a 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ go install github.com/MichaelS11/tetris Then run the binary created, tetris or tetris.exe -## Keys +## Keys during game | Key | Action | | --- | --- | @@ -30,6 +30,15 @@ Then run the binary created, tetris or tetris.exe | q | quit | | i | toggle AI | +## Keys start screen + +| Key | Action | +| --- | --- | +| ← | previous board | +| → | next board | +| spacebar | start game | +| q | quit | + ## Features include @@ -38,6 +47,7 @@ Then run the binary created, tetris or tetris.exe - Next piece - Ghost piece - Top scores +- Board choices ## Screenshots @@ -46,4 +56,11 @@ Then run the binary created, tetris or tetris.exe ![alt text](https://raw.githubusercontent.com/MichaelS11/tetris/master/screenshots/screenshot2.png "Golang Tetris") -![alt text](https://raw.githubusercontent.com/MichaelS11/tetris/master/screenshots/screenshot3.png "Tetris Top Scores") +![alt text](https://raw.githubusercontent.com/MichaelS11/tetris/master/screenshots/screenshot3.png "Golang Tetris Heart") + +![alt text](https://raw.githubusercontent.com/MichaelS11/tetris/master/screenshots/screenshot4.png "Tetris High Scores") + + +## To do + +* Improve AI speed (slow on large boards) diff --git a/ai.go b/ai.go index 587cb5b..e199427 100644 --- a/ai.go +++ b/ai.go @@ -1,26 +1,22 @@ package main -const ( - aiQueueSize = (boardWidth+1)/2 + 6 - aiMoveLength = (boardWidth + 1) / 2 -) - -type Ai struct { - queue [aiQueueSize]rune - index int -} - func NewAi() *Ai { ai := Ai{} - for i := 0; i < aiQueueSize; i++ { - ai.queue[i] = 'x' - } + queue := make([]rune, 1) + queue[0] = 'x' + ai.queue = &queue return &ai } -func (ai *Ai) ProcessQueue() bool { +func (ai *Ai) ProcessQueue() { + if ai.newQueue != nil { + ai.queue = ai.newQueue + ai.newQueue = nil + ai.index = 0 + } + queue := *ai.queue // wasd + qe keyboard keys - switch ai.queue[ai.index] { + switch queue[ai.index] { case 'w': board.MinoDrop() case 'a': @@ -32,51 +28,31 @@ func (ai *Ai) ProcessQueue() bool { case 'e': board.MinoRotateRight() case 'x': - return false + return } ai.index++ - if ai.index == aiQueueSize { - ai.index = 0 - } view.RefreshScreen() - return true } func (ai *Ai) GetBestQueue() { - ai.addMovesToQueue(ai.getBestQueue()) -} - -func (ai *Ai) addMovesToQueue(queue []rune) { - insertIndex := ai.index - for _, char := range queue { - ai.queue[insertIndex] = char - insertIndex++ - if insertIndex == aiQueueSize { - insertIndex = 0 - } - } -} - -func (ai *Ai) getBestQueue() []rune { - bestQueue := make([]rune, 0, 0) bestScore := -9999999 - var slideScore int - bestSlide := 6 + bestQueue := make([]rune, 0, 0) + currentMino := *board.currentMino - for move1 := 0; move1 <= boardWidth; move1++ { - for rotate1 := 0; rotate1 < 5; rotate1++ { - for slide1 := 0; slide1 <= 5; slide1++ { + for slide1 := 0; slide1 < 5; slide1++ { + for move1 := board.width; move1 >= 0; move1-- { + for rotate1 := 0; rotate1 < 5; rotate1++ { - queue, mino1 := ai.getMovesforMino(rotate1, move1, slide1, nil) + queue, mino1 := board.getMovesforMino(rotate1, move1, slide1, ¤tMino, nil) if mino1 == nil { continue } - for move2 := 0; move2 <= boardWidth; move2++ { - for rotate2 := 0; rotate2 < 5; rotate2++ { - for slide2 := 0; slide2 <= 5; slide2++ { + for slide2 := 0; slide2 < 5; slide2++ { + for move2 := board.width; move2 >= 0; move2-- { + for rotate2 := 0; rotate2 < 5; rotate2++ { - _, mino2 := ai.getMovesforMino(rotate2, move2, slide2, mino1) + _, mino2 := board.getMovesforMino(rotate2, move2, slide2, board.previewMino, mino1) if mino2 == nil { continue } @@ -84,16 +60,9 @@ func (ai *Ai) getBestQueue() []rune { fullLines, holes, bumpy := board.boardStatsWithMinos(mino1, mino2) score := ai.getScoreFromBoardStats(fullLines, holes, bumpy) - if slide1 < 3 { - slideScore = slide1 - } else { - slideScore = slide1 - 2 - } - - if score > bestScore || (score == bestScore && slideScore < bestSlide) { + if score > bestScore { bestScore = score bestQueue = queue - bestSlide = slideScore } } @@ -104,100 +73,95 @@ func (ai *Ai) getBestQueue() []rune { } } - return bestQueue + if len(bestQueue) < 1 { + bestQueue = append(bestQueue, 'x') + } + + ai.newQueue = &bestQueue } -func (ai *Ai) getMovesforMino(rotate int, move int, slide int, mino1 *Mino) ([]rune, *Mino) { +func (board *Board) getMovesforMino(rotate int, move int, slide int, mino1 *Mino, mino2 *Mino) ([]rune, *Mino) { queue := make([]rune, 0, 4) - var mino Mino - if mino1 != nil { - mino = *board.previewMino - } else { - mino = *board.currentMino - } - if rotate < 3 { + mino := *mino1 + + if rotate%2 == 0 { + rotate /= 2 for i := 0; i < rotate; i++ { mino.RotateRight() queue = append(queue, 'e') - if !mino.ValidLocation(false) || (mino1 != nil && mino1.minoOverlap(&mino)) { + if !mino.ValidLocation(false) || (mino2 != nil && mino2.minoOverlap(&mino)) { return queue, nil } } } else { - for i := 0; i < rotate-2; i++ { + rotate = rotate/2 + 1 + for i := 0; i < rotate; i++ { mino.RotateLeft() queue = append(queue, 'q') - if !mino.ValidLocation(false) || (mino1 != nil && mino1.minoOverlap(&mino)) { + if !mino.ValidLocation(false) || (mino2 != nil && mino2.minoOverlap(&mino)) { return queue, nil } } } - if move <= aiMoveLength { - move = aiMoveLength - move + + if move%2 == 0 { + move /= 2 for i := 0; i < move; i++ { mino.MoveLeft() queue = append(queue, 'a') - if !mino.ValidLocation(false) || (mino1 != nil && mino1.minoOverlap(&mino)) { + if !mino.ValidLocation(false) || (mino2 != nil && mino2.minoOverlap(&mino)) { return queue, nil } } } else { - move = move - aiMoveLength + 1 + move = move/2 + 1 for i := 0; i < move; i++ { mino.MoveRight() queue = append(queue, 'd') - if !mino.ValidLocation(false) || (mino1 != nil && mino1.minoOverlap(&mino)) { + if !mino.ValidLocation(false) || (mino2 != nil && mino2.minoOverlap(&mino)) { return queue, nil } } } - for mino.ValidLocation(false) && (mino1 == nil || !mino1.minoOverlap(&mino)) { + for mino.ValidLocation(false) && (mino2 == nil || !mino2.minoOverlap(&mino)) { mino.MoveDown() } mino.MoveUp() queue = append(queue, 'w') - if slide < 3 { + + if slide%2 == 0 { + slide /= 2 for i := 0; i < slide; i++ { mino.MoveLeft() queue = append(queue, 'a') - if !mino.ValidLocation(false) || (mino1 != nil && mino1.minoOverlap(&mino)) { + if !mino.ValidLocation(false) || (mino2 != nil && mino2.minoOverlap(&mino)) { return queue, nil } } } else { - slide = slide - 2 + slide = slide/2 + 1 for i := 0; i < slide; i++ { mino.MoveRight() queue = append(queue, 'd') - if !mino.ValidLocation(false) || (mino1 != nil && mino1.minoOverlap(&mino)) { + if !mino.ValidLocation(false) || (mino2 != nil && mino2.minoOverlap(&mino)) { return queue, nil } } } + + if !mino.ValidLocation(true) { + return queue, nil + } queue = append(queue, 'x') return queue, &mino } -func (mino *Mino) minoOverlap(mino1 *Mino) bool { - minoBlocks := mino.minoRotation[mino.rotation] - for i := 0; i < mino.length; i++ { - for j := 0; j < mino.length; j++ { - if minoBlocks[i][j] != blankColor { - if mino1.isMinoAtLocation(mino.x+i, mino.y+j) { - return true - } - } - } - } - return false -} - func (board *Board) boardStatsWithMinos(mino1 *Mino, mino2 *Mino) (fullLines int, holes int, bumpy int) { // fullLines fullLinesY := make(map[int]bool, 2) - for j := 0; j < boardHeight; j++ { + for j := 0; j < board.height; j++ { isFullLine := true - for i := 0; i < boardWidth; i++ { + for i := 0; i < board.width; i++ { if board.colors[i][j] == blankColor && !mino1.isMinoAtLocation(i, j) && !mino2.isMinoAtLocation(i, j) { isFullLine = false break @@ -211,10 +175,10 @@ func (board *Board) boardStatsWithMinos(mino1 *Mino, mino2 *Mino) (fullLines int // holes and bumpy indexLast := 0 - for i := 0; i < boardWidth; i++ { - index := boardHeight + for i := 0; i < board.width; i++ { + index := board.height indexOffset := 0 - for j := 0; j < boardHeight; j++ { + for j := 0; j < board.height; j++ { if _, found := fullLinesY[j]; found { indexOffset++ } else { @@ -236,7 +200,7 @@ func (board *Board) boardStatsWithMinos(mino1 *Mino, mino2 *Mino) (fullLines int indexLast = index + fullLines - indexOffset index++ - for j := index; j < boardHeight; j++ { + for j := index; j < board.height; j++ { if board.colors[i][j] == blankColor && !mino1.isMinoAtLocation(i, j) && !mino2.isMinoAtLocation(i, j) { holes++ } @@ -245,24 +209,9 @@ func (board *Board) boardStatsWithMinos(mino1 *Mino, mino2 *Mino) (fullLines int return } -func (mino *Mino) isMinoAtLocation(x int, y int) bool { - xIndex := x - mino.x - yIndex := y - mino.y - if xIndex < 0 || xIndex >= mino.length || yIndex < 0 || yIndex >= mino.length { - return false - } - - minoBlocks := mino.minoRotation[mino.rotation] - if minoBlocks[xIndex][yIndex] != blankColor { - return true - } - - return false -} - func (ai *Ai) getScoreFromBoardStats(fullLines int, holes int, bumpy int) (score int) { if fullLines == 4 { - score += 256 + score += 512 } score -= 75 * holes score -= 25 * bumpy diff --git a/ai_test.go b/ai_test.go index 054d91c..a41e986 100644 --- a/ai_test.go +++ b/ai_test.go @@ -1,494 +1,291 @@ package main import ( - "gopkg.in/inconshreveable/log15.v2" - "os" "testing" ) -func TestMain(m *testing.M) { - setupForTesting() - retCode := m.Run() - os.Exit(retCode) +type testAiStruct struct { + info string + minos []testMinoStruct + fullLines int + holes int + bumpy int } -func setupForTesting() { - logger = log15.New() - logger.SetHandler(log15.StreamHandler(os.Stdout, log15.LogfmtFormat())) +func TestAI(t *testing.T) { + // this must be set to the blank 10x20 board + board.boardsIndex = 0 + board.Clear() - engine = NewEngine() + tests := []testAiStruct{ + {info: "fullLines 2x minoI", minos: []testMinoStruct{ + testMinoStruct{minoRotation: minos.minoBag[0], x: 0, y: 18}, // minoI + testMinoStruct{minoRotation: minos.minoBag[0], x: 4, y: 18}, // minoI + }, fullLines: 0, holes: 0, bumpy: 1}, + {info: "fullLines 2x2 minoI", minos: []testMinoStruct{ + testMinoStruct{minoRotation: minos.minoBag[0], x: 0, y: 18}, // minoI + testMinoStruct{minoRotation: minos.minoBag[0], x: 4, y: 18}, // minoI + testMinoStruct{minoRotation: minos.minoBag[0], x: 0, y: 17}, // minoI + testMinoStruct{minoRotation: minos.minoBag[0], x: 4, y: 17}, // minoI + }, fullLines: 0, holes: 0, bumpy: 2}, + {info: "fullLines 2x minoI minoO", minos: []testMinoStruct{ + testMinoStruct{minoRotation: minos.minoBag[0], x: 0, y: 18}, // minoI + testMinoStruct{minoRotation: minos.minoBag[0], x: 4, y: 18}, // minoI + testMinoStruct{minoRotation: minos.minoBag[3], x: 8, y: 18}, // minoO + }, fullLines: 1, holes: 0, bumpy: 1}, + {info: "fullLines 2x2 minoI minoO", minos: []testMinoStruct{ + testMinoStruct{minoRotation: minos.minoBag[0], x: 0, y: 18}, // minoI + testMinoStruct{minoRotation: minos.minoBag[0], x: 4, y: 18}, // minoI + testMinoStruct{minoRotation: minos.minoBag[0], x: 0, y: 17}, // minoI + testMinoStruct{minoRotation: minos.minoBag[0], x: 4, y: 17}, // minoI + testMinoStruct{minoRotation: minos.minoBag[3], x: 8, y: 18}, // minoO + }, fullLines: 2, holes: 0, bumpy: 0}, + {info: "fullLines 5x minoO", minos: []testMinoStruct{ + testMinoStruct{minoRotation: minos.minoBag[3], x: 0, y: 18}, // minoO + testMinoStruct{minoRotation: minos.minoBag[3], x: 2, y: 18}, // minoO + testMinoStruct{minoRotation: minos.minoBag[3], x: 4, y: 18}, // minoO + testMinoStruct{minoRotation: minos.minoBag[3], x: 6, y: 18}, // minoO + testMinoStruct{minoRotation: minos.minoBag[3], x: 8, y: 18}, // minoO + }, fullLines: 2, holes: 0, bumpy: 0}, + {info: "fullLines 4x4 minoI 2x minoO", minos: []testMinoStruct{ + testMinoStruct{minoRotation: minos.minoBag[0], x: 0, y: 18}, // minoI + testMinoStruct{minoRotation: minos.minoBag[0], x: 4, y: 18}, // minoI + testMinoStruct{minoRotation: minos.minoBag[0], x: 0, y: 17}, // minoI + testMinoStruct{minoRotation: minos.minoBag[0], x: 4, y: 17}, // minoI + testMinoStruct{minoRotation: minos.minoBag[0], x: 0, y: 16}, // minoI + testMinoStruct{minoRotation: minos.minoBag[0], x: 4, y: 16}, // minoI + testMinoStruct{minoRotation: minos.minoBag[0], x: 0, y: 15}, // minoI + testMinoStruct{minoRotation: minos.minoBag[0], x: 4, y: 15}, // minoI + testMinoStruct{minoRotation: minos.minoBag[3], x: 8, y: 18}, // minoO + testMinoStruct{minoRotation: minos.minoBag[3], x: 8, y: 16}, // minoO + }, fullLines: 4, holes: 0, bumpy: 0}, + {info: "holes 2x minoI minoO", minos: []testMinoStruct{ + testMinoStruct{minoRotation: minos.minoBag[0], x: 0, y: 18}, // minoI + testMinoStruct{minoRotation: minos.minoBag[0], x: 6, y: 18}, // minoI + testMinoStruct{minoRotation: minos.minoBag[3], x: 4, y: 17}, // minoO + }, fullLines: 0, holes: 2, bumpy: 4}, + {info: "holes 6x minoO", minos: []testMinoStruct{ + testMinoStruct{minoRotation: minos.minoBag[3], x: 0, y: 18}, // minoO + testMinoStruct{minoRotation: minos.minoBag[3], x: 4, y: 18}, // minoO + testMinoStruct{minoRotation: minos.minoBag[3], x: 8, y: 18}, // minoO + testMinoStruct{minoRotation: minos.minoBag[3], x: 2, y: 16}, // minoO + testMinoStruct{minoRotation: minos.minoBag[3], x: 6, y: 16}, // minoO + }, fullLines: 0, holes: 8, bumpy: 8}, + {info: "holes 4x minoT 2x minoI", minos: []testMinoStruct{ + testMinoStruct{minoRotation: minos.minoBag[5], x: 0, y: 18}, // minoT + testMinoStruct{minoRotation: minos.minoBag[5], x: 7, y: 18}, // minoT + testMinoStruct{minoRotation: minos.minoBag[5], x: 3, y: 16}, // minoT + testMinoStruct{minoRotation: minos.minoBag[5], x: 7, y: 16}, // minoT + testMinoStruct{minoRotation: minos.minoBag[0], x: 2, y: 14}, // minoI + testMinoStruct{minoRotation: minos.minoBag[0], x: 6, y: 14}, // minoI + }, fullLines: 0, holes: 19, bumpy: 4}, + {info: "holes 3x minoZ", minos: []testMinoStruct{ + testMinoStruct{minoRotation: minos.minoBag[6], x: 0, y: 18}, // minoZ + testMinoStruct{minoRotation: minos.minoBag[6], x: 3, y: 18}, // minoZ + testMinoStruct{minoRotation: minos.minoBag[6], x: 6, y: 18}, // minoZ + }, fullLines: 0, holes: 3, bumpy: 6}, + {info: "bumpy 2x minoT - 1", minos: []testMinoStruct{ + testMinoStruct{minoRotation: minos.minoBag[5], x: 0, y: 18}, // minoT + testMinoStruct{minoRotation: minos.minoBag[5], x: 5, y: 18}, // minoT + }, fullLines: 0, holes: 0, bumpy: 7}, + {info: "bumpy 2x minoT - 2", minos: []testMinoStruct{ + testMinoStruct{minoRotation: minos.minoBag[5], x: 1, y: 18}, // minoT + testMinoStruct{minoRotation: minos.minoBag[5], x: 6, y: 18}, // minoT + }, fullLines: 0, holes: 0, bumpy: 8}, + {info: "bumpy 2x minoT - 3", minos: []testMinoStruct{ + testMinoStruct{minoRotation: minos.minoBag[5], x: 2, y: 18}, // minoT + testMinoStruct{minoRotation: minos.minoBag[5], x: 7, y: 18}, // minoT + }, fullLines: 0, holes: 0, bumpy: 7}, + {info: "bumpy 2x minoJ - 1", minos: []testMinoStruct{ + testMinoStruct{minoRotation: minos.minoBag[1], x: 0, y: 18}, // minoJ + testMinoStruct{minoRotation: minos.minoBag[1], x: 5, y: 18}, // minoJ + }, fullLines: 0, holes: 0, bumpy: 6}, + {info: "bumpy 2x minoJ - 2", minos: []testMinoStruct{ + testMinoStruct{minoRotation: minos.minoBag[1], x: 1, y: 18}, // minoJ + testMinoStruct{minoRotation: minos.minoBag[1], x: 6, y: 18}, // minoJ + }, fullLines: 0, holes: 0, bumpy: 8}, + {info: "bumpy 2x minoJ - 2", minos: []testMinoStruct{ + testMinoStruct{minoRotation: minos.minoBag[1], x: 2, y: 18}, // minoJ + testMinoStruct{minoRotation: minos.minoBag[1], x: 7, y: 18}, // minoJ + }, fullLines: 0, holes: 0, bumpy: 7}, + {info: "bumpy 2x minoL - 1", minos: []testMinoStruct{ + testMinoStruct{minoRotation: minos.minoBag[2], x: 0, y: 18}, // minoL + testMinoStruct{minoRotation: minos.minoBag[2], x: 5, y: 18}, // minoL + }, fullLines: 0, holes: 0, bumpy: 7}, + {info: "bumpy 2x minoL - 2", minos: []testMinoStruct{ + testMinoStruct{minoRotation: minos.minoBag[2], x: 1, y: 18}, // minoL + testMinoStruct{minoRotation: minos.minoBag[2], x: 6, y: 18}, // minoL + }, fullLines: 0, holes: 0, bumpy: 8}, + {info: "bumpy 2x minoL - 3", minos: []testMinoStruct{ + testMinoStruct{minoRotation: minos.minoBag[2], x: 2, y: 18}, // minoL + testMinoStruct{minoRotation: minos.minoBag[2], x: 7, y: 18}, // minoL + }, fullLines: 0, holes: 0, bumpy: 6}, + } + + runAiTests(t, tests) } -func TestBoardStatsFullLines1(t *testing.T) { - board = NewBoard() +func TestBigBoardAI(t *testing.T) { + // this must be set to the blank 20x20 board + board.boardsIndex = 3 + board.Clear() - // minoO - mino1 := &Mino{ - minoRotation: minoBag[3], - } - mino1.length = len(mino1.minoRotation[0]) - mino1.x = 0 - mino1.y = 18 - mino1.SetOnBoard() - - // minoI - mino1 = &Mino{ - minoRotation: minoBag[0], - } - mino1.length = len(mino1.minoRotation[0]) - mino1.x = 2 - mino1.y = 18 - - // minoI - mino2 := &Mino{ - minoRotation: minoBag[0], - } - mino2.length = len(mino2.minoRotation[0]) - mino2.x = 6 - mino2.y = 18 - - fullLines, holes, bumpy := board.boardStatsWithMinos(mino1, mino2) - expected := 1 - if fullLines != expected { - t.Error("fullLines expected", expected, "got", fullLines) - } - expected = 0 - if holes != expected { - t.Error("holes expected", expected, "got", holes) - } - expected = 1 - if bumpy != expected { - t.Error("bumpy expected", expected, "got", bumpy) + tests := []testAiStruct{ + {info: "fullLines 4x minoI", minos: []testMinoStruct{ + testMinoStruct{minoRotation: minos.minoBag[0], x: 0, y: 18}, // minoI + testMinoStruct{minoRotation: minos.minoBag[0], x: 4, y: 18}, // minoI + testMinoStruct{minoRotation: minos.minoBag[0], x: 8, y: 18}, // minoI + testMinoStruct{minoRotation: minos.minoBag[0], x: 12, y: 18}, // minoI + }, fullLines: 0, holes: 0, bumpy: 1}, + {info: "fullLines 5x minoI", minos: []testMinoStruct{ + testMinoStruct{minoRotation: minos.minoBag[0], x: 0, y: 18}, // minoI + testMinoStruct{minoRotation: minos.minoBag[0], x: 4, y: 18}, // minoI + testMinoStruct{minoRotation: minos.minoBag[0], x: 8, y: 18}, // minoI + testMinoStruct{minoRotation: minos.minoBag[0], x: 12, y: 18}, // minoI + testMinoStruct{minoRotation: minos.minoBag[0], x: 16, y: 18}, // minoI + }, fullLines: 1, holes: 0, bumpy: 0}, + {info: "fullLines 5x2 minoI", minos: []testMinoStruct{ + testMinoStruct{minoRotation: minos.minoBag[0], x: 0, y: 18}, // minoI + testMinoStruct{minoRotation: minos.minoBag[0], x: 4, y: 18}, // minoI + testMinoStruct{minoRotation: minos.minoBag[0], x: 8, y: 18}, // minoI + testMinoStruct{minoRotation: minos.minoBag[0], x: 12, y: 18}, // minoI + testMinoStruct{minoRotation: minos.minoBag[0], x: 16, y: 18}, // minoI + testMinoStruct{minoRotation: minos.minoBag[0], x: 0, y: 17}, // minoI + testMinoStruct{minoRotation: minos.minoBag[0], x: 4, y: 17}, // minoI + testMinoStruct{minoRotation: minos.minoBag[0], x: 8, y: 17}, // minoI + testMinoStruct{minoRotation: minos.minoBag[0], x: 12, y: 17}, // minoI + testMinoStruct{minoRotation: minos.minoBag[0], x: 16, y: 17}, // minoI + }, fullLines: 2, holes: 0, bumpy: 0}, + {info: "fullLines 9x minoO", minos: []testMinoStruct{ + testMinoStruct{minoRotation: minos.minoBag[3], x: 0, y: 18}, // minoO + testMinoStruct{minoRotation: minos.minoBag[3], x: 2, y: 18}, // minoO + testMinoStruct{minoRotation: minos.minoBag[3], x: 4, y: 18}, // minoO + testMinoStruct{minoRotation: minos.minoBag[3], x: 6, y: 18}, // minoO + testMinoStruct{minoRotation: minos.minoBag[3], x: 8, y: 18}, // minoO + testMinoStruct{minoRotation: minos.minoBag[3], x: 10, y: 18}, // minoO + testMinoStruct{minoRotation: minos.minoBag[3], x: 12, y: 18}, // minoO + testMinoStruct{minoRotation: minos.minoBag[3], x: 14, y: 18}, // minoO + testMinoStruct{minoRotation: minos.minoBag[3], x: 16, y: 18}, // minoO + }, fullLines: 0, holes: 0, bumpy: 2}, + {info: "fullLines 10x minoO", minos: []testMinoStruct{ + testMinoStruct{minoRotation: minos.minoBag[3], x: 0, y: 18}, // minoO + testMinoStruct{minoRotation: minos.minoBag[3], x: 2, y: 18}, // minoO + testMinoStruct{minoRotation: minos.minoBag[3], x: 4, y: 18}, // minoO + testMinoStruct{minoRotation: minos.minoBag[3], x: 6, y: 18}, // minoO + testMinoStruct{minoRotation: minos.minoBag[3], x: 8, y: 18}, // minoO + testMinoStruct{minoRotation: minos.minoBag[3], x: 10, y: 18}, // minoO + testMinoStruct{minoRotation: minos.minoBag[3], x: 12, y: 18}, // minoO + testMinoStruct{minoRotation: minos.minoBag[3], x: 14, y: 18}, // minoO + testMinoStruct{minoRotation: minos.minoBag[3], x: 16, y: 18}, // minoO + testMinoStruct{minoRotation: minos.minoBag[3], x: 18, y: 18}, // minoO + }, fullLines: 2, holes: 0, bumpy: 0}, + {info: "holes 3x minoO 3x minoI", minos: []testMinoStruct{ + testMinoStruct{minoRotation: minos.minoBag[3], x: 0, y: 18}, // minoO + testMinoStruct{minoRotation: minos.minoBag[3], x: 6, y: 18}, // minoO + testMinoStruct{minoRotation: minos.minoBag[3], x: 12, y: 18}, // minoO + testMinoStruct{minoRotation: minos.minoBag[0], x: 2, y: 16}, // minoI + testMinoStruct{minoRotation: minos.minoBag[0], x: 8, y: 16}, // minoI + testMinoStruct{minoRotation: minos.minoBag[0], x: 14, y: 16}, // minoI + }, fullLines: 0, holes: 24, bumpy: 8}, + {info: "holes 5x minoZ", minos: []testMinoStruct{ + testMinoStruct{minoRotation: minos.minoBag[6], x: 0, y: 18}, // minoZ + testMinoStruct{minoRotation: minos.minoBag[6], x: 4, y: 18}, // minoZ + testMinoStruct{minoRotation: minos.minoBag[6], x: 8, y: 18}, // minoZ + testMinoStruct{minoRotation: minos.minoBag[6], x: 12, y: 18}, // minoZ + testMinoStruct{minoRotation: minos.minoBag[6], x: 16, y: 18}, // minoZ + }, fullLines: 0, holes: 5, bumpy: 18}, + {info: "bumpy 4x minoJ - 1", minos: []testMinoStruct{ + testMinoStruct{minoRotation: minos.minoBag[1], x: 0, y: 18}, // minoJ + testMinoStruct{minoRotation: minos.minoBag[1], x: 5, y: 18}, // minoJ + testMinoStruct{minoRotation: minos.minoBag[1], x: 10, y: 18}, // minoJ + testMinoStruct{minoRotation: minos.minoBag[1], x: 15, y: 18}, // minoJ + }, fullLines: 0, holes: 0, bumpy: 14}, + {info: "bumpy 4x minoJ - 2", minos: []testMinoStruct{ + testMinoStruct{minoRotation: minos.minoBag[1], x: 1, y: 18}, // minoJ + testMinoStruct{minoRotation: minos.minoBag[1], x: 6, y: 18}, // minoJ + testMinoStruct{minoRotation: minos.minoBag[1], x: 11, y: 18}, // minoJ + testMinoStruct{minoRotation: minos.minoBag[1], x: 16, y: 18}, // minoJ + }, fullLines: 0, holes: 0, bumpy: 16}, + {info: "bumpy 4x minoJ - 3", minos: []testMinoStruct{ + testMinoStruct{minoRotation: minos.minoBag[1], x: 2, y: 18}, // minoJ + testMinoStruct{minoRotation: minos.minoBag[1], x: 7, y: 18}, // minoJ + testMinoStruct{minoRotation: minos.minoBag[1], x: 12, y: 18}, // minoJ + testMinoStruct{minoRotation: minos.minoBag[1], x: 17, y: 18}, // minoJ + }, fullLines: 0, holes: 0, bumpy: 15}, + {info: "bumpy 4x minoL - 1", minos: []testMinoStruct{ + testMinoStruct{minoRotation: minos.minoBag[2], x: 0, y: 18}, // minoL + testMinoStruct{minoRotation: minos.minoBag[2], x: 5, y: 18}, // minoL + testMinoStruct{minoRotation: minos.minoBag[2], x: 10, y: 18}, // minoL + testMinoStruct{minoRotation: minos.minoBag[2], x: 15, y: 18}, // minoL + }, fullLines: 0, holes: 0, bumpy: 15}, + {info: "bumpy 4x minoL - 2", minos: []testMinoStruct{ + testMinoStruct{minoRotation: minos.minoBag[2], x: 1, y: 18}, // minoL + testMinoStruct{minoRotation: minos.minoBag[2], x: 6, y: 18}, // minoL + testMinoStruct{minoRotation: minos.minoBag[2], x: 11, y: 18}, // minoL + testMinoStruct{minoRotation: minos.minoBag[2], x: 16, y: 18}, // minoL + }, fullLines: 0, holes: 0, bumpy: 16}, + {info: "bumpy 4x minoL - 3", minos: []testMinoStruct{ + testMinoStruct{minoRotation: minos.minoBag[2], x: 2, y: 18}, // minoL + testMinoStruct{minoRotation: minos.minoBag[2], x: 7, y: 18}, // minoL + testMinoStruct{minoRotation: minos.minoBag[2], x: 12, y: 18}, // minoL + testMinoStruct{minoRotation: minos.minoBag[2], x: 17, y: 18}, // minoL + }, fullLines: 0, holes: 0, bumpy: 14}, } - // for debuging - // mino1.SetOnBoard() - // mino2.SetOnBoard() - // board.drawDebugBoard() + runAiTests(t, tests) } -func TestBoardStatsFullLines2(t *testing.T) { - board = NewBoard() +func runAiTests(t *testing.T, tests []testAiStruct) { + var mino1 *Mino + var mino2 *Mino - // minoO - mino1 := &Mino{ - minoRotation: minoBag[3], - } - mino1.length = len(mino1.minoRotation[0]) - mino1.x = 0 - mino1.y = 18 - mino1.SetOnBoard() + for _, test := range tests { + board.Clear() - // minoO - mino1 = &Mino{ - minoRotation: minoBag[3], - } - mino1.length = len(mino1.minoRotation[0]) - mino1.x = 2 - mino1.y = 18 - mino1.SetOnBoard() + for i, minoTest := range test.minos { + mino := NewMino() + mino.minoRotation = minoTest.minoRotation + mino.length = len(mino.minoRotation[0]) + mino.x = minoTest.x + mino.y = minoTest.y + if i < len(test.minos)-2 { + mino.SetOnBoard() + } else if i == len(test.minos)-2 { + mino1 = mino + } else { + mino2 = mino + } + } - // minoO - mino1 = &Mino{ - minoRotation: minoBag[3], - } - mino1.length = len(mino1.minoRotation[0]) - mino1.x = 4 - mino1.y = 18 - mino1.SetOnBoard() + fullLines, holes, bumpy := board.boardStatsWithMinos(mino1, mino2) - // minoO - mino1 = &Mino{ - minoRotation: minoBag[3], - } - mino1.length = len(mino1.minoRotation[0]) - mino1.x = 6 - mino1.y = 18 - mino1.SetOnBoard() + if fullLines != test.fullLines { + mino1.SetOnBoard() + lines := board.getDebugBoardWithMino(mino2) + for i := 0; i < len(lines); i++ { + t.Log(lines[i]) + } + t.Errorf("AI fullLines - received: %v - expected: %v - info %v", fullLines, test.fullLines, test.info) + continue + } + if holes != test.holes { + mino1.SetOnBoard() + lines := board.getDebugBoardWithMino(mino2) + for i := 0; i < len(lines); i++ { + t.Log(lines[i]) + } + t.Errorf("AI holes - received: %v - expected: %v - info %v", holes, test.holes, test.info) + continue + } + if bumpy != test.bumpy { + mino1.SetOnBoard() + lines := board.getDebugBoardWithMino(mino2) + for i := 0; i < len(lines); i++ { + t.Log(lines[i]) + } + t.Errorf("AI bumpy - received: %v - expected: %v - info %v", bumpy, test.bumpy, test.info) + continue + } - // minoO - mino1 = &Mino{ - minoRotation: minoBag[3], } - mino1.length = len(mino1.minoRotation[0]) - mino1.x = 8 - mino1.y = 18 - mino1.SetOnBoard() - - // minoO - mino1 = &Mino{ - minoRotation: minoBag[3], - } - mino1.length = len(mino1.minoRotation[0]) - mino1.x = 0 - mino1.y = 16 - mino1.SetOnBoard() - - // minoI - mino1 = &Mino{ - minoRotation: minoBag[0], - } - mino1.length = len(mino1.minoRotation[0]) - mino1.x = 2 - mino1.y = 16 - - // minoI - mino2 := &Mino{ - minoRotation: minoBag[0], - } - mino2.length = len(mino2.minoRotation[0]) - mino2.x = 6 - mino2.y = 16 - - fullLines, holes, bumpy := board.boardStatsWithMinos(mino1, mino2) - expected := 3 - if fullLines != expected { - t.Error("fullLines expected", expected, "got", fullLines) - } - expected = 0 - if holes != expected { - t.Error("holes expected", expected, "got", holes) - } - expected = 1 - if bumpy != expected { - t.Error("bumpy expected", expected, "got", bumpy) - } - - // for debuging - // mino1.SetOnBoard() - // mino2.SetOnBoard() - // board.drawDebugBoard() -} - -func TestBoardStatsFullLines3(t *testing.T) { - board = NewBoard() - - // minoO - mino1 := &Mino{ - minoRotation: minoBag[3], - } - mino1.length = len(mino1.minoRotation[0]) - mino1.x = 0 - mino1.y = 18 - mino1.SetOnBoard() - - // minoI - mino1 = &Mino{ - minoRotation: minoBag[0], - } - mino1.length = len(mino1.minoRotation[0]) - mino1.x = 0 - mino1.y = 16 - mino1.SetOnBoard() - - // minoO - mino1 = &Mino{ - minoRotation: minoBag[3], - } - mino1.length = len(mino1.minoRotation[0]) - mino1.x = 4 - mino1.y = 18 - mino1.SetOnBoard() - - // minoI - mino1 = &Mino{ - minoRotation: minoBag[0], - } - mino1.length = len(mino1.minoRotation[0]) - mino1.x = 4 - mino1.y = 16 - mino1.SetOnBoard() - - // minoO - mino1 = &Mino{ - minoRotation: minoBag[3], - } - mino1.length = len(mino1.minoRotation[0]) - mino1.x = 8 - mino1.y = 18 - - // minoO - mino2 := &Mino{ - minoRotation: minoBag[3], - } - mino2.length = len(mino2.minoRotation[0]) - mino2.x = 8 - mino2.y = 16 - - fullLines, holes, bumpy := board.boardStatsWithMinos(mino1, mino2) - expected := 1 - if fullLines != expected { - t.Error("fullLines expected", expected, "got", fullLines) - } - expected = 0 - if holes != expected { - t.Error("holes expected", expected, "got", holes) - } - expected = 9 - if bumpy != expected { - t.Error("bumpy expected", expected, "got", bumpy) - } - - // for debuging - // mino1.SetOnBoard() - // mino2.SetOnBoard() - // board.drawDebugBoard() -} - -func TestBoardStatsBumpy1(t *testing.T) { - board = NewBoard() - - // minoO - mino1 := &Mino{ - minoRotation: minoBag[3], - } - mino1.length = len(mino1.minoRotation[0]) - mino1.x = 0 - mino1.y = 18 - - // minoO - mino2 := &Mino{ - minoRotation: minoBag[3], - } - mino2.length = len(mino2.minoRotation[0]) - mino2.x = 0 - mino2.y = 16 - - fullLines, holes, bumpy := board.boardStatsWithMinos(mino1, mino2) - expected := 0 - if fullLines != expected { - t.Error("fullLines expected", expected, "got", fullLines) - } - expected = 0 - if holes != expected { - t.Error("holes expected", expected, "got", holes) - } - expected = 4 - if bumpy != expected { - t.Error("bumpy expected", expected, "got", bumpy) - } - - // for debuging - // mino1.SetOnBoard() - // mino2.SetOnBoard() - // board.drawDebugBoard() -} - -func TestBoardStatsBumpy2(t *testing.T) { - board = NewBoard() - - // minoO - mino1 := &Mino{ - minoRotation: minoBag[3], - } - mino1.length = len(mino1.minoRotation[0]) - mino1.x = 0 - mino1.y = 18 - mino1.SetOnBoard() - - // minoI - mino1 = &Mino{ - minoRotation: minoBag[0], - } - mino1.length = len(mino1.minoRotation[0]) - mino1.x = 0 - mino1.y = 16 - - // minoI - mino2 := &Mino{ - minoRotation: minoBag[0], - } - mino2.length = len(mino2.minoRotation[0]) - mino2.x = 0 - mino2.y = 15 - - fullLines, holes, bumpy := board.boardStatsWithMinos(mino1, mino2) - expected := 0 - if fullLines != expected { - t.Error("fullLines expected", expected, "got", fullLines) - } - expected = 4 - if holes != expected { - t.Error("holes expected", expected, "got", holes) - } - expected = 4 - if bumpy != expected { - t.Error("bumpy expected", expected, "got", bumpy) - } - - // for debuging - // mino1.SetOnBoard() - // mino2.SetOnBoard() - // board.drawDebugBoard() -} - -func TestBoardStatsBumpy3(t *testing.T) { - board = NewBoard() - - // minoO - mino1 := &Mino{ - minoRotation: minoBag[3], - } - mino1.length = len(mino1.minoRotation[0]) - mino1.x = 0 - mino1.y = 18 - mino1.SetOnBoard() - - // minoO - mino1 = &Mino{ - minoRotation: minoBag[3], - } - mino1.length = len(mino1.minoRotation[0]) - mino1.x = 1 - mino1.y = 16 - - // minoO - mino2 := &Mino{ - minoRotation: minoBag[3], - } - mino2.length = len(mino2.minoRotation[0]) - mino2.x = 2 - mino2.y = 14 - - fullLines, holes, bumpy := board.boardStatsWithMinos(mino1, mino2) - expected := 0 - if fullLines != expected { - t.Error("fullLines expected", expected, "got", fullLines) - } - expected = 6 - if holes != expected { - t.Error("holes expected", expected, "got", holes) - } - expected = 10 - if bumpy != expected { - t.Error("bumpy expected", expected, "got", bumpy) - } - - // for debuging - // mino1.SetOnBoard() - // mino2.SetOnBoard() - // board.drawDebugBoard() -} - -func TestBoardStatsBumpy4(t *testing.T) { - board = NewBoard() - - // minoI - mino1 := &Mino{ - minoRotation: minoBag[0], - } - mino1.rotation = 1 - mino1.length = len(mino1.minoRotation[0]) - mino1.x = 6 - mino1.y = 16 - - // minoI - mino2 := &Mino{ - minoRotation: minoBag[0], - } - mino2.rotation = 1 - mino2.length = len(mino2.minoRotation[0]) - mino2.x = 6 - mino2.y = 12 - - fullLines, holes, bumpy := board.boardStatsWithMinos(mino1, mino2) - expected := 0 - if fullLines != expected { - t.Error("fullLines expected", expected, "got", fullLines) - } - expected = 0 - if holes != expected { - t.Error("holes expected", expected, "got", holes) - } - expected = 16 - if bumpy != expected { - t.Error("bumpy expected", expected, "got", bumpy) - } - - // for debuging - // mino1.SetOnBoard() - // mino2.SetOnBoard() - // board.drawDebugBoard() -} - -func TestBoardStatsholes1(t *testing.T) { - board = NewBoard() - - // minoJ - mino1 := &Mino{ - minoRotation: minoBag[1], - } - mino1.rotation = 1 - mino1.length = len(mino1.minoRotation[0]) - mino1.x = -1 - mino1.y = 17 - - // minoJ - mino2 := &Mino{ - minoRotation: minoBag[1], - } - mino2.rotation = 1 - mino2.length = len(mino2.minoRotation[0]) - mino2.x = 1 - mino2.y = 17 - - fullLines, holes, bumpy := board.boardStatsWithMinos(mino1, mino2) - expected := 0 - if fullLines != expected { - t.Error("fullLines expected", expected, "got", fullLines) - } - expected = 4 - if holes != expected { - t.Error("holes expected", expected, "got", holes) - } - expected = 3 - if bumpy != expected { - t.Error("bumpy expected", expected, "got", bumpy) - } - - // for debuging - // mino1.SetOnBoard() - // mino2.SetOnBoard() - // board.drawDebugBoard() -} - -func TestBoardStatsholes2(t *testing.T) { - board = NewBoard() - - // minoJ - mino1 := &Mino{ - minoRotation: minoBag[1], - } - mino1.rotation = 1 - mino1.length = len(mino1.minoRotation[0]) - mino1.x = -1 - mino1.y = 17 - - // minoJ - mino2 := &Mino{ - minoRotation: minoBag[1], - } - mino2.rotation = 1 - mino2.length = len(mino2.minoRotation[0]) - mino2.x = -1 - mino2.y = 14 - - fullLines, holes, bumpy := board.boardStatsWithMinos(mino1, mino2) - expected := 0 - if fullLines != expected { - t.Error("fullLines expected", expected, "got", fullLines) - } - expected = 4 - if holes != expected { - t.Error("holes expected", expected, "got", holes) - } - expected = 6 - if bumpy != expected { - t.Error("bumpy expected", expected, "got", bumpy) - } - - // for debuging - // mino1.SetOnBoard() - // mino2.SetOnBoard() - // board.drawDebugBoard() } diff --git a/board.go b/board.go index cea9bb5..e1e1637 100644 --- a/board.go +++ b/board.go @@ -2,33 +2,49 @@ package main import ( "fmt" - "github.com/nsf/termbox-go" "time" + + "github.com/nsf/termbox-go" ) -type Board struct { - colors [boardWidth][boardHeight]termbox.Attribute - rotation [boardWidth][boardHeight]int - previewMino *Mino - currentMino *Mino - dropDistance int +func NewBoard() { + board = &Board{} + board.Clear() } -func NewBoard() *Board { - board := &Board{} - for i := 0; i < boardWidth; i++ { - for j := 0; j < boardHeight; j++ { - board.colors[i][j] = blankColor - } +func (board *Board) Clear() { + board.width = len(boards[board.boardsIndex].colors) + board.height = len(boards[board.boardsIndex].colors[0]) + board.colors = make([][]termbox.Attribute, len(boards[board.boardsIndex].colors)) + for i := 0; i < len(boards[board.boardsIndex].colors); i++ { + board.colors[i] = make([]termbox.Attribute, len(boards[board.boardsIndex].colors[i])) + copy(board.colors[i], boards[board.boardsIndex].colors[i]) } - for i := 0; i < boardWidth; i++ { - for j := 0; j < boardHeight; j++ { - board.rotation[i][j] = 0 - } + board.rotation = make([][]int, len(boards[board.boardsIndex].rotation)) + for i := 0; i < len(boards[board.boardsIndex].rotation); i++ { + board.rotation[i] = make([]int, len(boards[board.boardsIndex].rotation[i])) + copy(board.rotation[i], boards[board.boardsIndex].rotation[i]) } board.previewMino = NewMino() board.currentMino = NewMino() - return board +} + +func (board *Board) PreviousBoard() { + board.boardsIndex-- + if board.boardsIndex < 0 { + board.boardsIndex = len(boards) - 1 + } + engine.PreviewBoard() + board.Clear() +} + +func (board *Board) NextBoard() { + board.boardsIndex++ + if board.boardsIndex == len(boards) { + board.boardsIndex = 0 + } + engine.PreviewBoard() + board.Clear() } func (board *Board) MinoMoveLeft() { @@ -160,7 +176,7 @@ func (board *Board) nextMino() { board.currentMino = board.previewMino board.previewMino = NewMino() - engine.ResetAiTimer() + engine.AiGetBestQueue() engine.ResetTimer(0) } @@ -180,7 +196,7 @@ func (board *Board) deleteCheck() { func (board *Board) fullLines() []int { fullLines := make([]int, 0, 1) - for j := 0; j < boardHeight; j++ { + for j := 0; j < board.height; j++ { if board.isFullLine(j) { fullLines = append(fullLines, j) } @@ -189,7 +205,7 @@ func (board *Board) fullLines() []int { } func (board *Board) isFullLine(j int) bool { - for i := 0; i < boardWidth; i++ { + for i := 0; i < board.width; i++ { if board.colors[i][j] == blankColor { return false } @@ -198,16 +214,16 @@ func (board *Board) isFullLine(j int) bool { } func (board *Board) deleteLine(line int) { - for i := 0; i < boardWidth; i++ { + for i := 0; i < board.width; i++ { board.colors[i][line] = blankColor } for j := line; j > 0; j-- { - for i := 0; i < boardWidth; i++ { + for i := 0; i < board.width; i++ { board.colors[i][j] = board.colors[i][j-1] board.rotation[i][j] = board.rotation[i][j-1] } } - for i := 0; i < boardWidth; i++ { + for i := 0; i < board.width; i++ { board.colors[i][0] = blankColor } } @@ -218,7 +234,7 @@ func (board *Board) SetColor(x int, y int, color termbox.Attribute, rotation int } func ValidBlockLocation(x int, y int, mustBeOnBoard bool) bool { - if x < 0 || x >= boardWidth || y >= boardHeight { + if x < 0 || x >= board.width || y >= board.height { return false } if mustBeOnBoard { @@ -239,12 +255,12 @@ func ValidBlockLocation(x int, y int, mustBeOnBoard bool) bool { } func ValidDisplayLocation(x int, y int) bool { - return x >= 0 && x < boardWidth && y >= 0 && y < boardHeight + return x >= 0 && x < board.width && y >= 0 && y < board.height } func (board *Board) DrawBoard() { - for i := 0; i < boardWidth; i++ { - for j := 0; j < boardHeight; j++ { + for i := 0; i < board.width; i++ { + for j := 0; j < board.height; j++ { if board.colors[i][j] != blankColor { view.DrawBlock(i, j, board.colors[i][j], board.rotation[i][j]) } @@ -273,9 +289,9 @@ func (board *Board) DrawDropMino() { } // for debuging -func (board *Board) drawDebugBoard() { - for j := 0; j < boardHeight; j++ { - for i := 0; i < boardWidth; i++ { +func (board *Board) printDebugBoard() { + for j := 0; j < board.height; j++ { + for i := 0; i < board.width; i++ { switch board.colors[i][j] { case blankColor: fmt.Print(".") @@ -293,8 +309,89 @@ func (board *Board) drawDebugBoard() { fmt.Print("W") case termbox.ColorYellow: fmt.Print("Y") + default: + fmt.Print("U") } } fmt.Println("") } } + +// for debuging +func (board *Board) getDebugBoard() []string { + lines := make([]string, board.height) + for j := 0; j < board.height; j++ { + for i := 0; i < board.width; i++ { + switch board.colors[i][j] { + case blankColor: + lines[j] += "." + case termbox.ColorBlue: + lines[j] += "B" + case termbox.ColorCyan: + lines[j] += "C" + case termbox.ColorGreen: + lines[j] += "G" + case termbox.ColorMagenta: + lines[j] += "M" + case termbox.ColorRed: + lines[j] += "R" + case termbox.ColorWhite: + lines[j] += "W" + case termbox.ColorYellow: + lines[j] += "Y" + default: + lines[j] += "U" + } + } + } + return lines +} + +// for debuging +func (board *Board) getDebugBoardWithMino(mino *Mino) []string { + lines := make([]string, board.height) + for j := 0; j < board.height; j++ { + for i := 0; i < board.width; i++ { + switch mino.getMinoColorAtLocation(i, j) { + case blankColor: + switch board.colors[i][j] { + case blankColor: + lines[j] += "." + case termbox.ColorBlue: + lines[j] += "B" + case termbox.ColorCyan: + lines[j] += "C" + case termbox.ColorGreen: + lines[j] += "G" + case termbox.ColorMagenta: + lines[j] += "M" + case termbox.ColorRed: + lines[j] += "R" + case termbox.ColorWhite: + lines[j] += "W" + case termbox.ColorYellow: + lines[j] += "Y" + default: + lines[j] += "U" + } + case termbox.ColorBlue: + lines[j] += "b" + case termbox.ColorCyan: + lines[j] += "c" + case termbox.ColorGreen: + lines[j] += "g" + case termbox.ColorMagenta: + lines[j] += "m" + case termbox.ColorRed: + lines[j] += "r" + case termbox.ColorWhite: + lines[j] += "w" + case termbox.ColorYellow: + lines[j] += "y" + default: + lines[j] += "u" + } + } + } + return lines +} diff --git a/boards.go b/boards.go new file mode 100644 index 0000000..a467a5f --- /dev/null +++ b/boards.go @@ -0,0 +1,1086 @@ +package main + +import ( + "github.com/nsf/termbox-go" +) + +func init() { + boards = []Boards{ + + // 10 x 20 blank + Boards{ + colors: [][]termbox.Attribute{ + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + }, + rotation: [][]int{ + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + }}, + + // 10 x 20 checkerboard double + Boards{ + colors: [][]termbox.Attribute{ + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, + termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, + termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, + blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, + blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, + termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, + termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, + blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, + blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, + termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, + termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed}, + }, + rotation: [][]int{ + []int{0, 0, 0, 0, 0, 0, 2, 2, 0, 0, + 2, 2, 0, 0, 2, 2, 0, 0, 2, 2}, + []int{0, 0, 0, 0, 0, 0, 2, 2, 0, 0, + 2, 2, 0, 0, 2, 2, 0, 0, 2, 2}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 2, 2, 0, 0, + 2, 2, 0, 0, 2, 2, 0, 0, 2, 2}, + []int{0, 0, 0, 0, 0, 0, 2, 2, 0, 0, + 2, 2, 0, 0, 2, 2, 0, 0, 2, 2}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 2, 2, 0, 0, + 2, 2, 0, 0, 2, 2, 0, 0, 2, 2}, + []int{0, 0, 0, 0, 0, 0, 2, 2, 0, 0, + 2, 2, 0, 0, 2, 2, 0, 0, 2, 2}, + }}, + + // 10 x 20 checkerboard single + Boards{ + colors: [][]termbox.Attribute{ + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, + blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, + termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, + blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, + termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, + blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, + termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, + blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, + termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, + blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, + termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor}, + }, + rotation: [][]int{ + []int{0, 0, 0, 2, 0, 2, 0, 2, 0, 2, + 0, 2, 0, 2, 0, 2, 0, 2, 0, 2}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 2, 0, 2, 0, 2, 0, 2, + 0, 2, 0, 2, 0, 2, 0, 2, 0, 2}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 2, 0, 2, 0, 2, 0, 2, + 0, 2, 0, 2, 0, 2, 0, 2, 0, 2}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 2, 0, 2, 0, 2, 0, 2, + 0, 2, 0, 2, 0, 2, 0, 2, 0, 2}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 2, 0, 2, 0, 2, 0, 2, + 0, 2, 0, 2, 0, 2, 0, 2, 0, 2}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + }}, + + // 20 x 20 blank + Boards{ + colors: [][]termbox.Attribute{ + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + }, + rotation: [][]int{ + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + }}, + + // 20 x 20 heart + Boards{ + colors: [][]termbox.Attribute{ + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorWhite, + termbox.ColorWhite, termbox.ColorWhite, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, + termbox.ColorMagenta, termbox.ColorWhite, termbox.ColorYellow, termbox.ColorYellow, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, termbox.ColorMagenta, + termbox.ColorMagenta, termbox.ColorMagenta, termbox.ColorYellow, termbox.ColorYellow, termbox.ColorBlue, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorWhite, termbox.ColorWhite, termbox.ColorWhite, + termbox.ColorCyan, termbox.ColorCyan, termbox.ColorCyan, termbox.ColorCyan, termbox.ColorBlue, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorGreen, termbox.ColorGreen, termbox.ColorWhite, + termbox.ColorWhite, termbox.ColorWhite, termbox.ColorRed, termbox.ColorRed, termbox.ColorBlue, termbox.ColorBlue, blankColor, blankColor, blankColor, blankColor}, + + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorGreen, termbox.ColorGreen, + termbox.ColorWhite, termbox.ColorRed, termbox.ColorRed, termbox.ColorCyan, termbox.ColorCyan, termbox.ColorCyan, termbox.ColorCyan, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorBlue, termbox.ColorBlue, + termbox.ColorWhite, termbox.ColorGreen, termbox.ColorGreen, termbox.ColorMagenta, termbox.ColorMagenta, termbox.ColorMagenta, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorGreen, termbox.ColorBlue, + termbox.ColorYellow, termbox.ColorYellow, termbox.ColorGreen, termbox.ColorGreen, termbox.ColorMagenta, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, blankColor}, + + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorGreen, termbox.ColorGreen, termbox.ColorBlue, + termbox.ColorYellow, termbox.ColorYellow, termbox.ColorYellow, termbox.ColorYellow, termbox.ColorWhite, termbox.ColorWhite, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorGreen, termbox.ColorRed, termbox.ColorRed, + termbox.ColorGreen, termbox.ColorGreen, termbox.ColorYellow, termbox.ColorYellow, termbox.ColorWhite, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, termbox.ColorMagenta, + termbox.ColorBlue, termbox.ColorGreen, termbox.ColorGreen, termbox.ColorBlue, termbox.ColorWhite, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorMagenta, termbox.ColorMagenta, + termbox.ColorBlue, termbox.ColorBlue, termbox.ColorBlue, termbox.ColorBlue, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorMagenta, + termbox.ColorBlue, termbox.ColorBlue, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + }, + rotation: [][]int{ + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 2, + 2, 2, 0, 0, 2, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2, 2, 2, 2, 2, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2, 2, 0, 0, 2, 2, 0, 0, 0, 0}, + + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2, 0, 0, 0, 0, 0, 2, 2, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2, 2, 0, 0, 0, 2, 2, 0, 0, 0}, + + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2, 2, 0, 0, 2, 2, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2, 2, 0, 0, 2, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2, 2, 2, 2, 2, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2, 2, 2, 2, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2, 2, 0, 0, 0, 0, 0, 0, 0, 0}, + + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + }}, + + // 20 x 20 checkerboard double + Boards{ + colors: [][]termbox.Attribute{ + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, + termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, + termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, + blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, + blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, + termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, + termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, + blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, + blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, + termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, + termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed}, + + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, + blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, + blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, + termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, + termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, + blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, + blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, + termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, + termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, + blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, + blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor}, + }, + rotation: [][]int{ + []int{0, 0, 0, 0, 0, 0, 2, 2, 0, 0, + 2, 2, 0, 0, 2, 2, 0, 0, 2, 2}, + []int{0, 0, 0, 0, 0, 0, 2, 2, 0, 0, + 2, 2, 0, 0, 2, 2, 0, 0, 2, 2}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 2, 2, 0, 0, + 2, 2, 0, 0, 2, 2, 0, 0, 2, 2}, + []int{0, 0, 0, 0, 0, 0, 2, 2, 0, 0, + 2, 2, 0, 0, 2, 2, 0, 0, 2, 2}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 2, 2, 0, 0, + 2, 2, 0, 0, 2, 2, 0, 0, 2, 2}, + []int{0, 0, 0, 0, 0, 0, 2, 2, 0, 0, + 2, 2, 0, 0, 2, 2, 0, 0, 2, 2}, + + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 2, 2, 0, 0, + 2, 2, 0, 0, 2, 2, 0, 0, 2, 2}, + []int{0, 0, 0, 0, 0, 0, 2, 2, 0, 0, + 2, 2, 0, 0, 2, 2, 0, 0, 2, 2}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 2, 2, 0, 0, + 2, 2, 0, 0, 2, 2, 0, 0, 2, 2}, + []int{0, 0, 0, 0, 0, 0, 2, 2, 0, 0, + 2, 2, 0, 0, 2, 2, 0, 0, 2, 2}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + }}, + + // 20 x 20 checkerboard single + Boards{ + colors: [][]termbox.Attribute{ + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, + blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, + termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, + blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, + termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, + blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, + termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, + blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, + termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, + blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, + termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor}, + + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, + blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, + termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, + blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, + termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, + blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, + termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, + blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, + termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, + blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, + termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor}, + }, + rotation: [][]int{ + []int{0, 0, 0, 2, 0, 2, 0, 2, 0, 2, + 0, 2, 0, 2, 0, 2, 0, 2, 0, 2}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 2, 0, 2, 0, 2, 0, 2, + 0, 2, 0, 2, 0, 2, 0, 2, 0, 2}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 2, 0, 2, 0, 2, 0, 2, + 0, 2, 0, 2, 0, 2, 0, 2, 0, 2}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 2, 0, 2, 0, 2, 0, 2, + 0, 2, 0, 2, 0, 2, 0, 2, 0, 2}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 2, 0, 2, 0, 2, 0, 2, + 0, 2, 0, 2, 0, 2, 0, 2, 0, 2}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + + []int{0, 0, 0, 2, 0, 2, 0, 2, 0, 2, + 0, 2, 0, 2, 0, 2, 0, 2, 0, 2}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 2, 0, 2, 0, 2, 0, 2, + 0, 2, 0, 2, 0, 2, 0, 2, 0, 2}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 2, 0, 2, 0, 2, 0, 2, + 0, 2, 0, 2, 0, 2, 0, 2, 0, 2}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 2, 0, 2, 0, 2, 0, 2, + 0, 2, 0, 2, 0, 2, 0, 2, 0, 2}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 2, 0, 2, 0, 2, 0, 2, + 0, 2, 0, 2, 0, 2, 0, 2, 0, 2}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + }}, + + // 30 x 30 blank + Boards{ + colors: [][]termbox.Attribute{ + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, + blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor}, + }, + rotation: [][]int{ + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + }}, + + // 30 x 30 checkerboard double + Boards{ + colors: [][]termbox.Attribute{ + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, + blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, + termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, + blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, + termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, + termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, + blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, + termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, + blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, + blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, + termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, + blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, + termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, + termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, + blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, + termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, + blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, + blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, + termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, + blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, + termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed}, + + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, + termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, + blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, + termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, + blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, + blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, + termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, + blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, + termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, + termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, + blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, + termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, + blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, + blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, + termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, + blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, + termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, + termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, + blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, + termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, + blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor}, + + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, + blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, + termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, + blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, + termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, + termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, + blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, + termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, + blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, + blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, + termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, + blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, + termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, + termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, + blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, + termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, + blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, + blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, + termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, + blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, + termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed, blankColor, blankColor, termbox.ColorRed, termbox.ColorRed}, + }, + rotation: [][]int{ + []int{0, 0, 0, 0, 0, 0, 0, 0, 2, 2, + 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, + 2, 2, 0, 0, 2, 2, 0, 0, 2, 2}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 2, 2, + 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, + 2, 2, 0, 0, 2, 2, 0, 0, 2, 2}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 2, 2, + 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, + 2, 2, 0, 0, 2, 2, 0, 0, 2, 2}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 2, 2, + 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, + 2, 2, 0, 0, 2, 2, 0, 0, 2, 2}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 2, 2, + 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, + 2, 2, 0, 0, 2, 2, 0, 0, 2, 2}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 2, 2, + 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, + 2, 2, 0, 0, 2, 2, 0, 0, 2, 2}, + + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 2, 2, + 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, + 2, 2, 0, 0, 2, 2, 0, 0, 2, 2}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 2, 2, + 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, + 2, 2, 0, 0, 2, 2, 0, 0, 2, 2}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 2, 2, + 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, + 2, 2, 0, 0, 2, 2, 0, 0, 2, 2}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 2, 2, + 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, + 2, 2, 0, 0, 2, 2, 0, 0, 2, 2}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + + []int{0, 0, 0, 0, 0, 0, 0, 0, 2, 2, + 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, + 2, 2, 0, 0, 2, 2, 0, 0, 2, 2}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 2, 2, + 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, + 2, 2, 0, 0, 2, 2, 0, 0, 2, 2}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 2, 2, + 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, + 2, 2, 0, 0, 2, 2, 0, 0, 2, 2}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 2, 2, + 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, + 2, 2, 0, 0, 2, 2, 0, 0, 2, 2}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 2, 2, + 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, + 2, 2, 0, 0, 2, 2, 0, 0, 2, 2}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 2, 2, + 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, + 2, 2, 0, 0, 2, 2, 0, 0, 2, 2}, + }}, + + // 30 x 30 checkerboard single + Boards{ + colors: [][]termbox.Attribute{ + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, + blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, + blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, + termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, + termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, + blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, + blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, + termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, + termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, + blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, + blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, + termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, + termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, + blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, + blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, + termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, + termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, + blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, + blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, + termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, + termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor}, + + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, + blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, + blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, + termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, + termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, + blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, + blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, + termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, + termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, + blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, + blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, + termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, + termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, + blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, + blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, + termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, + termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, + blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, + blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, + termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, + termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor}, + + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, + blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, + blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, + termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, + termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, + blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, + blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, + termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, + termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, + blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, + blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, + termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, + termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, + blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, + blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, + termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, + termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, + blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, + blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed}, + []termbox.Attribute{blankColor, blankColor, blankColor, blankColor, blankColor, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, + termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, + termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor, termbox.ColorRed, blankColor}, + }, + rotation: [][]int{ + []int{0, 0, 0, 0, 0, 0, 0, 2, 0, 2, + 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, + 0, 2, 0, 2, 0, 2, 0, 2, 0, 2}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 2, 0, 2, + 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, + 0, 2, 0, 2, 0, 2, 0, 2, 0, 2}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 2, 0, 2, + 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, + 0, 2, 0, 2, 0, 2, 0, 2, 0, 2}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 2, 0, 2, + 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, + 0, 2, 0, 2, 0, 2, 0, 2, 0, 2}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 2, 0, 2, + 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, + 0, 2, 0, 2, 0, 2, 0, 2, 0, 2}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + + []int{0, 0, 0, 0, 0, 0, 0, 2, 0, 2, + 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, + 0, 2, 0, 2, 0, 2, 0, 2, 0, 2}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 2, 0, 2, + 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, + 0, 2, 0, 2, 0, 2, 0, 2, 0, 2}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 2, 0, 2, + 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, + 0, 2, 0, 2, 0, 2, 0, 2, 0, 2}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 2, 0, 2, + 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, + 0, 2, 0, 2, 0, 2, 0, 2, 0, 2}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 2, 0, 2, + 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, + 0, 2, 0, 2, 0, 2, 0, 2, 0, 2}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + + []int{0, 0, 0, 0, 0, 0, 0, 2, 0, 2, + 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, + 0, 2, 0, 2, 0, 2, 0, 2, 0, 2}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 2, 0, 2, + 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, + 0, 2, 0, 2, 0, 2, 0, 2, 0, 2}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 2, 0, 2, + 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, + 0, 2, 0, 2, 0, 2, 0, 2, 0, 2}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 2, 0, 2, + 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, + 0, 2, 0, 2, 0, 2, 0, 2, 0, 2}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + []int{0, 0, 0, 0, 0, 0, 0, 2, 0, 2, + 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, + 0, 2, 0, 2, 0, 2, 0, 2, 0, 2}, + []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + }}, + } +} diff --git a/boards_test.go b/boards_test.go new file mode 100644 index 0000000..937a097 --- /dev/null +++ b/boards_test.go @@ -0,0 +1,30 @@ +package main + +import ( + "testing" +) + +func TestBoards(t *testing.T) { + for i := 0; i < len(boards); i++ { + b := boards[i] + width := len(b.colors) + height := len(b.colors[0]) + + for j := 1; j < width; j++ { + if len(b.colors[j]) != height { + t.Fatalf("board height - received: %v - expected: %v - index %v", len(b.colors[j]), height, i) + } + } + + if len(b.rotation) != width { + t.Fatalf("rotation width - received: %v - expected: %v - index %v", len(b.rotation), width, i) + } + + for j := 0; j < width; j++ { + if len(b.rotation[j]) != height { + t.Fatalf("rotation height - received: %v - expected: %v - index %v", len(b.rotation[j]), height, i) + } + } + + } +} diff --git a/engine.go b/engine.go index 0a3711f..e344feb 100644 --- a/engine.go +++ b/engine.go @@ -1,29 +1,13 @@ package main import ( - "github.com/nsf/termbox-go" "time" + + "github.com/nsf/termbox-go" ) -type Engine struct { - stopped bool - chanStop chan struct{} - keyInput *KeyInput - ranking *Ranking - timer *time.Timer - tickTime time.Duration - paused bool - gameOver bool - score int - level int - deleteLines int - ai *Ai - aiEnabled bool - aiTimer *time.Timer -} - -func NewEngine() *Engine { - return &Engine{ +func NewEngine() { + engine = &Engine{ chanStop: make(chan struct{}, 1), gameOver: true, tickTime: time.Hour, @@ -42,7 +26,7 @@ func (engine *Engine) Run() { engine.aiTimer.Stop() engine.ranking = NewRanking() - board = NewBoard() + board.Clear() view.RefreshScreen() engine.keyInput = NewKeyInput() @@ -61,9 +45,8 @@ loop: case <-engine.timer.C: engine.tick() case <-engine.aiTimer.C: - if engine.ai.ProcessQueue() { - engine.aiTimer.Reset(engine.tickTime / 4) - } + engine.ai.ProcessQueue() + engine.aiTimer.Reset(engine.tickTime / 6) case <-engine.chanStop: break loop } @@ -105,15 +88,19 @@ func (engine *Engine) Pause() { func (engine *Engine) UnPause() { engine.timer.Reset(engine.tickTime) if engine.aiEnabled { - engine.aiTimer.Reset(engine.tickTime / 4) + engine.aiTimer.Reset(engine.tickTime / 6) } engine.paused = false } +func (engine *Engine) PreviewBoard() { + engine.previewBoard = true +} + func (engine *Engine) NewGame() { logger.Info("Engine NewGame start") - board = NewBoard() + board.Clear() engine.tickTime = 480 * time.Millisecond engine.score = 0 engine.level = 1 @@ -128,6 +115,7 @@ loop: } } + engine.previewBoard = false engine.gameOver = false if engine.aiEnabled { engine.ai.GetBestQueue() @@ -153,12 +141,11 @@ func (engine *Engine) ResetTimer(duration time.Duration) { } } -func (engine *Engine) ResetAiTimer() { +func (engine *Engine) AiGetBestQueue() { if !engine.aiEnabled { return } - engine.ai.GetBestQueue() - engine.aiTimer.Reset(engine.tickTime / 4) + go engine.ai.GetBestQueue() } func (engine *Engine) tick() { @@ -190,8 +177,8 @@ func (engine *Engine) AddDeleteLines(lines int) { func (engine *Engine) AddScore(add int) { engine.score += add - if engine.score > 999999 { - engine.score = 999999 + if engine.score > 9999999 { + engine.score = 9999999 } } @@ -222,13 +209,9 @@ func (engine *Engine) GameOver() { logger.Info("Engine GameOver start") engine.Pause() - - view.ShowGameOverAnimation() - engine.gameOver = true - engine.ranking.InsertScore(uint64(engine.score)) - engine.ranking.Save() + view.ShowGameOverAnimation() loop: for { @@ -239,21 +222,24 @@ loop: } } + engine.ranking.InsertScore(uint64(engine.score)) + engine.ranking.Save() + logger.Info("Engine GameOver end") } func (engine *Engine) EnabledAi() { engine.aiEnabled = true - engine.ai.GetBestQueue() - engine.aiTimer.Reset(engine.tickTime / 4) + go engine.ai.GetBestQueue() + engine.aiTimer.Reset(engine.tickTime / 6) } func (engine *Engine) DisableAi() { + engine.aiEnabled = false if !engine.aiTimer.Stop() { select { case <-engine.aiTimer.C: default: } } - engine.aiEnabled = false } diff --git a/globals.go b/globals.go new file mode 100644 index 0000000..74e15c9 --- /dev/null +++ b/globals.go @@ -0,0 +1,103 @@ +package main + +import ( + "time" + + "github.com/nsf/termbox-go" + "gopkg.in/inconshreveable/log15.v2" +) + +const ( + blankColor = termbox.ColorBlack + boardXOffset = 4 + boardYOffset = 2 + rankingFileName = "/tetris.db" + + MinoPreview MinoType = iota + MinoCurrent = iota + MinoDrop = iota +) + +type ( + MinoType int + MinoBlocks [][]termbox.Attribute + MinoRotation [4]MinoBlocks + + Mino struct { + x int + y int + length int + rotation int + minoRotation MinoRotation + } + + Minos struct { + minoBag [7]MinoRotation + bagRand []int + bagIndex int + } + + Board struct { + boardsIndex int + width int + height int + colors [][]termbox.Attribute + rotation [][]int + previewMino *Mino + currentMino *Mino + dropDistance int + } + + Boards struct { + colors [][]termbox.Attribute + rotation [][]int + } + + KeyInput struct { + stopped bool + chanStop chan struct{} + chanKeyInput chan *termbox.Event + } + + View struct { + } + + Ai struct { + queue *[]rune + newQueue *[]rune + index int + } + + Ranking struct { + scores []uint64 + } + + Engine struct { + stopped bool + chanStop chan struct{} + keyInput *KeyInput + ranking *Ranking + timer *time.Timer + tickTime time.Duration + paused bool + gameOver bool + previewBoard bool + score int + level int + deleteLines int + ai *Ai + aiEnabled bool + aiTimer *time.Timer + } +) + +var ( + boards []Boards + + baseDir string + logger log15.Logger + minos *Minos + board *Board + view *View + engine *Engine +) diff --git a/keyInput.go b/keyInput.go index 7a09dc4..ecf1131 100644 --- a/keyInput.go +++ b/keyInput.go @@ -1,15 +1,10 @@ package main import ( - "github.com/nsf/termbox-go" "runtime" -) -type KeyInput struct { - stopped bool - chanStop chan struct{} - chanKeyInput chan *termbox.Event -} + "github.com/nsf/termbox-go" +) func NewKeyInput() *KeyInput { return &KeyInput{ @@ -29,16 +24,11 @@ loop: default: } event := termbox.PollEvent() - if event.Type == termbox.EventKey { + if event.Type == termbox.EventKey && len(keyInput.chanKeyInput) < 8 { select { case <-keyInput.chanStop: break loop - default: - select { - case keyInput.chanKeyInput <- &event: - case <-keyInput.chanStop: - break loop - } + case keyInput.chanKeyInput <- &event: } } } @@ -47,7 +37,6 @@ loop: } func (keyInput *KeyInput) ProcessEvent(event *termbox.Event) { - if event.Key == termbox.KeyCtrlI { // ctrl i to log stack trace buffer := make([]byte, 1<<16) @@ -66,8 +55,15 @@ func (keyInput *KeyInput) ProcessEvent(event *termbox.Event) { } if engine.gameOver { - if event.Key == termbox.KeySpace { - engine.NewGame() + if event.Ch == 0 { + switch event.Key { + case termbox.KeySpace: + engine.NewGame() + case termbox.KeyArrowLeft: + board.PreviousBoard() + case termbox.KeyArrowRight: + board.NextBoard() + } } return } diff --git a/mino.go b/mino.go index e6cd68c..5b63df3 100644 --- a/mino.go +++ b/mino.go @@ -2,47 +2,22 @@ package main import ( "math/rand" - "time" + + "github.com/nsf/termbox-go" ) -type MinoType int - -const ( - MinoPreview MinoType = iota - MinoCurrent = iota - MinoDrop = iota -) - -var ( - bagRand []int - bagIndex int -) - -func init() { - rand.Seed(time.Now().UnixNano()) - bagRand = rand.Perm(7) -} - -type Mino struct { - x int - y int - length int - rotation int - minoRotation MinoRotation -} - func NewMino() *Mino { - minoRotation := minoBag[bagRand[bagIndex]] - bagIndex++ - if bagIndex > 6 { - bagIndex = 0 - bagRand = rand.Perm(7) + minoRotation := minos.minoBag[minos.bagRand[minos.bagIndex]] + minos.bagIndex++ + if minos.bagIndex > 6 { + minos.bagIndex = 0 + minos.bagRand = rand.Perm(7) } mino := &Mino{ minoRotation: minoRotation, length: len(minoRotation[0]), } - mino.x = boardWidth/2 - (mino.length+1)/2 + mino.x = board.width/2 - (mino.length+1)/2 mino.y = -1 return mino } @@ -152,3 +127,43 @@ func (mino *Mino) DrawMino(minoType MinoType) { } } } + +func (mino *Mino) minoOverlap(mino1 *Mino) bool { + minoBlocks := mino.minoRotation[mino.rotation] + for i := 0; i < mino.length; i++ { + for j := 0; j < mino.length; j++ { + if minoBlocks[i][j] != blankColor { + if mino1.isMinoAtLocation(mino.x+i, mino.y+j) { + return true + } + } + } + } + return false +} + +func (mino *Mino) isMinoAtLocation(x int, y int) bool { + xIndex := x - mino.x + yIndex := y - mino.y + if xIndex < 0 || xIndex >= mino.length || yIndex < 0 || yIndex >= mino.length { + return false + } + + minoBlocks := mino.minoRotation[mino.rotation] + if minoBlocks[xIndex][yIndex] != blankColor { + return true + } + + return false +} + +func (mino *Mino) getMinoColorAtLocation(x int, y int) termbox.Attribute { + xIndex := x - mino.x + yIndex := y - mino.y + if xIndex < 0 || xIndex >= mino.length || yIndex < 0 || yIndex >= mino.length { + return blankColor + } + + minoBlocks := mino.minoRotation[mino.rotation] + return minoBlocks[xIndex][yIndex] +} diff --git a/mino_test.go b/mino_test.go new file mode 100644 index 0000000..71d6650 --- /dev/null +++ b/mino_test.go @@ -0,0 +1,120 @@ +package main + +import ( + "math/rand" + "os" + "testing" + + "gopkg.in/inconshreveable/log15.v2" +) + +type testMinoStruct struct { + minoRotation MinoRotation + x int + y int +} + +func TestMain(m *testing.M) { + setupForTesting() + retCode := m.Run() + os.Exit(retCode) +} + +func setupForTesting() { + logger = log15.New() + logger.SetHandler(log15.StreamHandler(os.Stdout, log15.LogfmtFormat())) + + rand.Seed(1) + + NewMinos() + NewBoard() + NewEngine() +} + +func TestMinoValidLocation(t *testing.T) { + // this must be set to the blank boards + for _, i := range []int{0, 3} { + board.boardsIndex = i + board.Clear() + + tests := []struct { + info string + mino testMinoStruct + changeLocation bool + mustBeOnBoard bool + validLocation bool + }{ + {info: "start 0 false", mino: testMinoStruct{minoRotation: minos.minoBag[0]}, mustBeOnBoard: false, validLocation: true}, + {info: "start 0 true", mino: testMinoStruct{minoRotation: minos.minoBag[0]}, mustBeOnBoard: true, validLocation: true}, + {info: "start 1 false", mino: testMinoStruct{minoRotation: minos.minoBag[1]}, mustBeOnBoard: false, validLocation: true}, + {info: "start 1 true", mino: testMinoStruct{minoRotation: minos.minoBag[1]}, mustBeOnBoard: true, validLocation: false}, + {info: "start 2 false", mino: testMinoStruct{minoRotation: minos.minoBag[2]}, mustBeOnBoard: false, validLocation: true}, + {info: "start 2 true", mino: testMinoStruct{minoRotation: minos.minoBag[2]}, mustBeOnBoard: true, validLocation: false}, + {info: "start 3 false", mino: testMinoStruct{minoRotation: minos.minoBag[3]}, mustBeOnBoard: false, validLocation: true}, + {info: "start 3 true", mino: testMinoStruct{minoRotation: minos.minoBag[3]}, mustBeOnBoard: true, validLocation: false}, + {info: "start 4 false", mino: testMinoStruct{minoRotation: minos.minoBag[4]}, mustBeOnBoard: false, validLocation: true}, + {info: "start 4 true", mino: testMinoStruct{minoRotation: minos.minoBag[4]}, mustBeOnBoard: true, validLocation: false}, + {info: "start 5 false", mino: testMinoStruct{minoRotation: minos.minoBag[5]}, mustBeOnBoard: false, validLocation: true}, + {info: "start 5 true", mino: testMinoStruct{minoRotation: minos.minoBag[5]}, mustBeOnBoard: true, validLocation: false}, + {info: "start 6 false", mino: testMinoStruct{minoRotation: minos.minoBag[6]}, mustBeOnBoard: false, validLocation: true}, + {info: "start 6 true", mino: testMinoStruct{minoRotation: minos.minoBag[6]}, mustBeOnBoard: true, validLocation: false}, + + {info: "top left 3 false", mino: testMinoStruct{minoRotation: minos.minoBag[3], x: 0, y: 0}, changeLocation: true, mustBeOnBoard: false, validLocation: true}, + {info: "top left 3 true", mino: testMinoStruct{minoRotation: minos.minoBag[3], x: 0, y: 0}, changeLocation: true, mustBeOnBoard: true, validLocation: true}, + {info: "top right 3 false", mino: testMinoStruct{minoRotation: minos.minoBag[3], x: board.width - 2, y: 0}, changeLocation: true, mustBeOnBoard: false, validLocation: true}, + {info: "top right 3 true", mino: testMinoStruct{minoRotation: minos.minoBag[3], x: board.width - 2, y: 0}, changeLocation: true, mustBeOnBoard: true, validLocation: true}, + {info: "bottom right 3 false", mino: testMinoStruct{minoRotation: minos.minoBag[3], x: board.width - 2, y: board.height - 2}, changeLocation: true, mustBeOnBoard: false, validLocation: true}, + {info: "bottom right 3 true", mino: testMinoStruct{minoRotation: minos.minoBag[3], x: board.width - 2, y: board.height - 2}, changeLocation: true, mustBeOnBoard: true, validLocation: true}, + {info: "bottom left 3 false", mino: testMinoStruct{minoRotation: minos.minoBag[3], x: 0, y: board.height - 2}, changeLocation: true, mustBeOnBoard: false, validLocation: true}, + {info: "bottom left 3 true", mino: testMinoStruct{minoRotation: minos.minoBag[3], x: 0, y: board.height - 2}, changeLocation: true, mustBeOnBoard: true, validLocation: true}, + + {info: "up 1 top left 3 false", mino: testMinoStruct{minoRotation: minos.minoBag[3], x: 0, y: -1}, changeLocation: true, mustBeOnBoard: false, validLocation: true}, + {info: "up 1 top left 3 true", mino: testMinoStruct{minoRotation: minos.minoBag[3], x: 0, y: -1}, changeLocation: true, mustBeOnBoard: true, validLocation: false}, + {info: "up 1 top right 3 false", mino: testMinoStruct{minoRotation: minos.minoBag[3], x: board.width - 2, y: -1}, changeLocation: true, mustBeOnBoard: false, validLocation: true}, + {info: "up 1 top right 3 true", mino: testMinoStruct{minoRotation: minos.minoBag[3], x: board.width - 2, y: -1}, changeLocation: true, mustBeOnBoard: true, validLocation: false}, + + {info: "up 2 top left 3 false", mino: testMinoStruct{minoRotation: minos.minoBag[3], x: 0, y: -2}, changeLocation: true, mustBeOnBoard: false, validLocation: true}, + {info: "up 2 top left 3 true", mino: testMinoStruct{minoRotation: minos.minoBag[3], x: 0, y: -2}, changeLocation: true, mustBeOnBoard: true, validLocation: false}, + {info: "up 2 top right 3 false", mino: testMinoStruct{minoRotation: minos.minoBag[3], x: board.width - 2, y: -2}, changeLocation: true, mustBeOnBoard: false, validLocation: true}, + {info: "up 2 top right 3 true", mino: testMinoStruct{minoRotation: minos.minoBag[3], x: board.width - 2, y: -2}, changeLocation: true, mustBeOnBoard: true, validLocation: false}, + + {info: "up 3 top left 3 false", mino: testMinoStruct{minoRotation: minos.minoBag[3], x: 0, y: -3}, changeLocation: true, mustBeOnBoard: false, validLocation: false}, + {info: "up 3 top left 3 true", mino: testMinoStruct{minoRotation: minos.minoBag[3], x: 0, y: -3}, changeLocation: true, mustBeOnBoard: true, validLocation: false}, + {info: "up 3 top right 3 false", mino: testMinoStruct{minoRotation: minos.minoBag[3], x: board.width - 2, y: -3}, changeLocation: true, mustBeOnBoard: false, validLocation: false}, + {info: "up 3 top right 3 true", mino: testMinoStruct{minoRotation: minos.minoBag[3], x: board.width - 2, y: -3}, changeLocation: true, mustBeOnBoard: true, validLocation: false}, + + {info: "off top left 3 false", mino: testMinoStruct{minoRotation: minos.minoBag[3], x: -1, y: 0}, changeLocation: true, mustBeOnBoard: false, validLocation: false}, + {info: "off top left 3 true", mino: testMinoStruct{minoRotation: minos.minoBag[3], x: -1, y: 0}, changeLocation: true, mustBeOnBoard: true, validLocation: false}, + {info: "off top right 3 false", mino: testMinoStruct{minoRotation: minos.minoBag[3], x: board.width - 1, y: 0}, changeLocation: true, mustBeOnBoard: false, validLocation: false}, + {info: "off top right 3 true", mino: testMinoStruct{minoRotation: minos.minoBag[3], x: board.width - 1, y: 0}, changeLocation: true, mustBeOnBoard: true, validLocation: false}, + {info: "off bottom right 3 false", mino: testMinoStruct{minoRotation: minos.minoBag[3], x: board.width - 1, y: board.height - 2}, changeLocation: true, mustBeOnBoard: false, validLocation: false}, + {info: "off bottom right 3 true", mino: testMinoStruct{minoRotation: minos.minoBag[3], x: board.width - 1, y: board.height - 2}, changeLocation: true, mustBeOnBoard: true, validLocation: false}, + {info: "off bottom right 3 false", mino: testMinoStruct{minoRotation: minos.minoBag[3], x: board.width - 2, y: board.height - 1}, changeLocation: true, mustBeOnBoard: false, validLocation: false}, + {info: "off bottom right 3 true", mino: testMinoStruct{minoRotation: minos.minoBag[3], x: board.width - 2, y: board.height - 1}, changeLocation: true, mustBeOnBoard: true, validLocation: false}, + {info: "off bottom left 3 false", mino: testMinoStruct{minoRotation: minos.minoBag[3], x: -1, y: board.height - 2}, changeLocation: true, mustBeOnBoard: false, validLocation: false}, + {info: "off bottom left 3 true", mino: testMinoStruct{minoRotation: minos.minoBag[3], x: -1, y: board.height - 2}, changeLocation: true, mustBeOnBoard: true, validLocation: false}, + {info: "off bottom left 3 false", mino: testMinoStruct{minoRotation: minos.minoBag[3], x: 0, y: board.height - 1}, changeLocation: true, mustBeOnBoard: false, validLocation: false}, + {info: "off bottom left 3 true", mino: testMinoStruct{minoRotation: minos.minoBag[3], x: 0, y: board.height - 1}, changeLocation: true, mustBeOnBoard: true, validLocation: false}, + } + + for _, test := range tests { + mino := NewMino() + mino.minoRotation = test.mino.minoRotation + mino.length = len(mino.minoRotation[0]) + if test.changeLocation { + mino.x = test.mino.x + mino.y = test.mino.y + } + validLocation := mino.ValidLocation(test.mustBeOnBoard) + if validLocation != test.validLocation { + lines := board.getDebugBoardWithMino(mino) + for i := 0; i < len(lines); i++ { + t.Log(lines[i]) + } + t.Errorf("MinoValidLocation validLocation - received: %v - expected: %v - info %v", validLocation, test.validLocation, test.info) + } + } + + } + +} diff --git a/minos.go b/minos.go index 2bafd4c..8cf19f7 100644 --- a/minos.go +++ b/minos.go @@ -1,16 +1,12 @@ package main import ( + "math/rand" + "github.com/nsf/termbox-go" ) -type MinoBlocks [][]termbox.Attribute - -type MinoRotation [4]MinoBlocks - -var minoBag [7]MinoRotation - -func init() { +func NewMinos() { minoI := MinoBlocks{ []termbox.Attribute{blankColor, termbox.ColorCyan, blankColor, blankColor}, []termbox.Attribute{blankColor, termbox.ColorCyan, blankColor, blankColor}, @@ -50,17 +46,17 @@ func init() { var minoRotationI MinoRotation minoRotationI[0] = minoI for i := 1; i < 4; i++ { - minoRotationI[i] = initCloneRotateRight(minoRotationI[i-1]) + minoRotationI[i] = minosCloneRotateRight(minoRotationI[i-1]) } var minoRotationJ MinoRotation minoRotationJ[0] = minoJ for i := 1; i < 4; i++ { - minoRotationJ[i] = initCloneRotateRight(minoRotationJ[i-1]) + minoRotationJ[i] = minosCloneRotateRight(minoRotationJ[i-1]) } var minoRotationL MinoRotation minoRotationL[0] = minoL for i := 1; i < 4; i++ { - minoRotationL[i] = initCloneRotateRight(minoRotationL[i-1]) + minoRotationL[i] = minosCloneRotateRight(minoRotationL[i-1]) } var minoRotationO MinoRotation minoRotationO[0] = minoO @@ -70,23 +66,26 @@ func init() { var minoRotationS MinoRotation minoRotationS[0] = minoS for i := 1; i < 4; i++ { - minoRotationS[i] = initCloneRotateRight(minoRotationS[i-1]) + minoRotationS[i] = minosCloneRotateRight(minoRotationS[i-1]) } var minoRotationT MinoRotation minoRotationT[0] = minoT for i := 1; i < 4; i++ { - minoRotationT[i] = initCloneRotateRight(minoRotationT[i-1]) + minoRotationT[i] = minosCloneRotateRight(minoRotationT[i-1]) } var minoRotationZ MinoRotation minoRotationZ[0] = minoZ for i := 1; i < 4; i++ { - minoRotationZ[i] = initCloneRotateRight(minoRotationZ[i-1]) + minoRotationZ[i] = minosCloneRotateRight(minoRotationZ[i-1]) } - minoBag = [7]MinoRotation{minoRotationI, minoRotationJ, minoRotationL, minoRotationO, minoRotationS, minoRotationT, minoRotationZ} + minos = &Minos{ + minoBag: [7]MinoRotation{minoRotationI, minoRotationJ, minoRotationL, minoRotationO, minoRotationS, minoRotationT, minoRotationZ}, + bagRand: rand.Perm(7), + } } -func initCloneRotateRight(minoBlocks MinoBlocks) MinoBlocks { +func minosCloneRotateRight(minoBlocks MinoBlocks) MinoBlocks { length := len(minoBlocks) newMinoBlocks := make(MinoBlocks, length, length) for i := 0; i < length; i++ { diff --git a/ranking.go b/ranking.go index 4500607..2dd3a7b 100644 --- a/ranking.go +++ b/ranking.go @@ -8,21 +8,13 @@ import ( "strings" ) -const ( - rankingFileName = "/tetris.db" -) - -type Ranking struct { - scores []uint64 -} - func NewRanking() *Ranking { ranking := &Ranking{ - scores: make([]uint64, 10), + scores: make([]uint64, 9), } if _, err := os.Stat(baseDir + rankingFileName); os.IsNotExist(err) { - for i := 0; i < 10; i++ { + for i := 0; i < 9; i++ { ranking.scores[i] = 0 } return ranking @@ -35,6 +27,9 @@ func NewRanking() *Ranking { scoreStrings := strings.Split(string(scoreBytes), ",") for index, scoreString := range scoreStrings { + if index > 8 { + break + } score, err := strconv.ParseUint(scoreString, 10, 64) if err != nil { logger.Error("NewRanking ParseUint", "error", err.Error()) @@ -49,7 +44,7 @@ func NewRanking() *Ranking { func (ranking *Ranking) Save() { var buffer bytes.Buffer - for i := 0; i < 10; i++ { + for i := 0; i < 9; i++ { if i != 0 { buffer.WriteRune(',') } diff --git a/screenshots/screenshot3.png b/screenshots/screenshot3.png index dd423a95fa7b29e34abbb2d86d6911212f519f6a..a9f4016016f7f25ce273308386f1e48f9b1502a4 100644 GIT binary patch literal 8040 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 X7gg?A!@(Ct8YhpL8|5DP{qny7OeDAU literal 6134 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 Rc0^oca~5ccJALuSzXAMYTH^o! literal 0 HcmV?d00001 diff --git a/tetris.go b/tetris.go index c3909fa..3fce15a 100644 --- a/tetris.go +++ b/tetris.go @@ -1,24 +1,12 @@ package main import ( - "github.com/nsf/termbox-go" - "gopkg.in/inconshreveable/log15.v2" + "math/rand" "os" "path/filepath" -) + "time" -const ( - boardWidth = 10 - boardHeight = 20 - blankColor = termbox.ColorBlack -) - -var ( - baseDir string - logger log15.Logger - view *View - engine *Engine - board *Board + "gopkg.in/inconshreveable/log15.v2" ) func main() { @@ -29,8 +17,12 @@ func main() { logger.SetHandler(log15.Must.FileHandler(baseDir+"/tetris.log", log15.LogfmtFormat())) } - view = NewView() - engine = NewEngine() + rand.Seed(time.Now().UnixNano()) + + NewMinos() + NewBoard() + NewView() + NewEngine() engine.Run() diff --git a/view.go b/view.go index 073dfc5..9be12cc 100644 --- a/view.go +++ b/view.go @@ -2,27 +2,20 @@ package main import ( "fmt" - "github.com/nsf/termbox-go" + "math/rand" "time" + + "github.com/nsf/termbox-go" ) -const ( - boardXOffset = 4 - boardYOffset = 2 -) - -type View struct { - drawDropMarkerDisabled bool -} - -func NewView() *View { +func NewView() { err := termbox.Init() if err != nil { panic(err) } termbox.SetInputMode(termbox.InputEsc) termbox.Flush() - return &View{} + view = &View{} } func (view *View) Stop() { @@ -38,12 +31,18 @@ func (view *View) RefreshScreen() { view.drawBackground() view.drawTexts() - board.DrawPreviewMino() - if engine.gameOver { + if engine.previewBoard { + board.DrawBoard() view.drawGameOver() + } else if engine.gameOver { + view.drawGameOver() + view.drawRankingScores() + } else if engine.paused { + view.drawPaused() } else { board.DrawBoard() + board.DrawPreviewMino() board.DrawDropMino() board.DrawCurrentMino() } @@ -55,8 +54,8 @@ func (view *View) drawBackground() { // playing board xOffset := boardXOffset yOffset := boardYOffset - xEnd := boardXOffset + boardWidth*2 + 4 - yEnd := boardYOffset + boardHeight + 2 + xEnd := boardXOffset + board.width*2 + 4 + yEnd := boardYOffset + board.height + 2 for x := xOffset; x < xEnd; x++ { for y := yOffset; y < yEnd; y++ { if x == xOffset || x == xOffset+1 || x == xEnd-1 || x == xEnd-2 || @@ -69,7 +68,7 @@ func (view *View) drawBackground() { } // piece preview - xOffset = boardXOffset + boardWidth*2 + 8 + xOffset = boardXOffset + board.width*2 + 8 yOffset = boardYOffset xEnd = xOffset + 14 yEnd = yOffset + 6 @@ -87,7 +86,7 @@ func (view *View) drawBackground() { } func (view *View) drawTexts() { - xOffset := boardXOffset + boardWidth*2 + 8 + xOffset := boardXOffset + board.width*2 + 8 yOffset := boardYOffset + 7 view.drawText(xOffset, yOffset, "SCORE:", termbox.ColorWhite, termbox.ColorBlue) @@ -135,7 +134,7 @@ func (view *View) DrawPreviewMinoBlock(x int, y int, color termbox.Attribute, ro char1 = ' ' char2 = '▓' } - xOffset := 2*x + 2*boardWidth + boardXOffset + 11 + (4 - length) + xOffset := 2*x + 2*board.width + boardXOffset + 11 + (4 - length) termbox.SetCell(xOffset, y+boardYOffset+2, char1, color, color^termbox.AttrBold) termbox.SetCell(xOffset+1, y+boardYOffset+2, char2, color, color^termbox.AttrBold) } @@ -160,17 +159,32 @@ func (view *View) DrawBlock(x int, y int, color termbox.Attribute, rotation int) } } -func (view *View) drawGameOver() { - xOffset := boardXOffset + 4 - yOffset := boardYOffset + 2 +func (view *View) drawPaused() { + yOffset := (board.height+1)/2 + boardYOffset + view.drawTextCenter(yOffset, "Paused", termbox.ColorWhite, termbox.ColorBlack) +} - view.drawText(xOffset, yOffset, " GAME OVER", termbox.ColorWhite, termbox.ColorBlack) +func (view *View) drawGameOver() { + yOffset := boardYOffset + 2 + view.drawTextCenter(yOffset, " GAME OVER", termbox.ColorWhite, termbox.ColorBlack) yOffset += 2 - view.drawText(xOffset, yOffset, "sbar for new game", termbox.ColorWhite, termbox.ColorBlack) + view.drawTextCenter(yOffset, "sbar for new game", termbox.ColorWhite, termbox.ColorBlack) + + if engine.previewBoard { + return + } + yOffset += 2 - xOffset += 2 + // ascii arrow characters add extra two spaces + view.drawTextCenter(yOffset, "←previous board", termbox.ColorWhite, termbox.ColorBlack) + yOffset += 2 + view.drawTextCenter(yOffset, "→next board", termbox.ColorWhite, termbox.ColorBlack) +} + +func (view *View) drawRankingScores() { + yOffset := boardYOffset + 10 for index, line := range engine.ranking.scores { - view.drawText(xOffset, yOffset+index, fmt.Sprintf("%2d: %6d", index+1, line), termbox.ColorWhite, termbox.ColorBlack) + view.drawTextCenter(yOffset+index, fmt.Sprintf("%1d: %6d", index+1, line), termbox.ColorWhite, termbox.ColorBlack) } } @@ -180,9 +194,14 @@ func (view *View) drawText(x int, y int, text string, fg termbox.Attribute, bg t } } -func (view *View) ShowDeleteAnimation(lines []int) { - view.drawDropMarkerDisabled = true +func (view *View) drawTextCenter(y int, text string, fg termbox.Attribute, bg termbox.Attribute) { + xOffset := board.width - (len(text)+1)/2 + boardXOffset + 2 + for index, char := range text { + termbox.SetCell(index+xOffset, y, rune(char), fg, bg) + } +} +func (view *View) ShowDeleteAnimation(lines []int) { view.RefreshScreen() for times := 0; times < 3; times++ { @@ -195,26 +214,77 @@ func (view *View) ShowDeleteAnimation(lines []int) { view.RefreshScreen() time.Sleep(140 * time.Millisecond) } - - view.drawDropMarkerDisabled = false } func (view *View) ShowGameOverAnimation() { - view.drawDropMarkerDisabled = true + logger.Info("View ShowGameOverAnimation start") - view.RefreshScreen() + switch rand.Intn(3) { + case 0: + for y := board.height - 1; y >= 0; y-- { + view.colorizeLine(y, termbox.ColorBlack) + termbox.Flush() + time.Sleep(60 * time.Millisecond) + } - for y := boardHeight - 1; y >= 0; y-- { - view.colorizeLine(y, termbox.ColorBlack) - termbox.Flush() - time.Sleep(60 * time.Millisecond) + case 1: + for y := 0; y < board.height; y++ { + view.colorizeLine(y, termbox.ColorBlack) + termbox.Flush() + time.Sleep(60 * time.Millisecond) + } + + case 2: + sleepTime := 50 * time.Millisecond + topStartX := boardXOffset + 3 + topEndX := board.width*2 + boardXOffset + 1 + topY := boardYOffset + 1 + rightStartY := boardYOffset + 1 + rightEndY := board.height + boardYOffset + 1 + rightX := board.width*2 + boardXOffset + 1 + bottomStartX := topEndX - 1 + bottomEndX := topStartX - 1 + bottomY := board.height + boardYOffset + leftStartY := rightEndY - 1 + leftEndY := rightStartY - 1 + leftX := boardXOffset + 2 + + for topStartX <= topEndX && rightStartY <= rightEndY { + for x := topStartX; x < topEndX; x++ { + termbox.SetCell(x, topY, ' ', termbox.ColorBlack, termbox.ColorBlack) + } + topStartX++ + topEndX-- + topY++ + for y := rightStartY; y < rightEndY; y++ { + termbox.SetCell(rightX, y, ' ', termbox.ColorBlack, termbox.ColorBlack) + } + rightStartY++ + rightEndY-- + rightX-- + for x := bottomStartX; x > bottomEndX; x-- { + termbox.SetCell(x, bottomY, ' ', termbox.ColorBlack, termbox.ColorBlack) + } + bottomStartX-- + bottomEndX++ + bottomY-- + for y := leftStartY; y > leftEndY; y-- { + termbox.SetCell(leftX, y, ' ', termbox.ColorBlack, termbox.ColorBlack) + } + leftStartY-- + leftEndY++ + leftX++ + termbox.Flush() + time.Sleep(sleepTime) + sleepTime += 4 * time.Millisecond + } } - view.drawDropMarkerDisabled = false + logger.Info("View ShowGameOverAnimation end") } func (view *View) colorizeLine(y int, color termbox.Attribute) { - for x := 0; x < boardWidth; x++ { + for x := 0; x < board.width; x++ { termbox.SetCell(x*2+boardXOffset+2, y+boardYOffset+1, ' ', termbox.ColorDefault, color) termbox.SetCell(x*2+boardXOffset+3, y+boardYOffset+1, ' ', termbox.ColorDefault, color) }