301 lines
5.9 KiB
Go
301 lines
5.9 KiB
Go
|
package main
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"github.com/nsf/termbox-go"
|
||
|
"time"
|
||
|
)
|
||
|
|
||
|
type Board struct {
|
||
|
colors [boardWidth][boardHeight]termbox.Attribute
|
||
|
rotation [boardWidth][boardHeight]int
|
||
|
previewMino *Mino
|
||
|
currentMino *Mino
|
||
|
dropDistance int
|
||
|
}
|
||
|
|
||
|
func NewBoard() *Board {
|
||
|
board := &Board{}
|
||
|
for i := 0; i < boardWidth; i++ {
|
||
|
for j := 0; j < boardHeight; j++ {
|
||
|
board.colors[i][j] = blankColor
|
||
|
}
|
||
|
}
|
||
|
for i := 0; i < boardWidth; i++ {
|
||
|
for j := 0; j < boardHeight; j++ {
|
||
|
board.rotation[i][j] = 0
|
||
|
}
|
||
|
}
|
||
|
board.previewMino = NewMino()
|
||
|
board.currentMino = NewMino()
|
||
|
return board
|
||
|
}
|
||
|
|
||
|
func (board *Board) MinoMoveLeft() {
|
||
|
board.dropDistance = 0
|
||
|
mino := board.currentMino.CloneMoveLeft()
|
||
|
if mino.ValidLocation(false) {
|
||
|
board.currentMino = mino
|
||
|
board.StartLockDelayIfBottom()
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (board *Board) MinoMoveRight() {
|
||
|
board.dropDistance = 0
|
||
|
mino := board.currentMino.CloneMoveRight()
|
||
|
if mino.ValidLocation(false) {
|
||
|
board.currentMino = mino
|
||
|
board.StartLockDelayIfBottom()
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (board *Board) MinoRotateRight() {
|
||
|
board.dropDistance = 0
|
||
|
mino := board.currentMino.CloneRotateRight()
|
||
|
if mino.ValidLocation(false) {
|
||
|
board.currentMino = mino
|
||
|
board.StartLockDelayIfBottom()
|
||
|
return
|
||
|
}
|
||
|
mino.MoveLeft()
|
||
|
if mino.ValidLocation(false) {
|
||
|
board.currentMino = mino
|
||
|
board.StartLockDelayIfBottom()
|
||
|
return
|
||
|
}
|
||
|
mino.MoveRight()
|
||
|
mino.MoveRight()
|
||
|
if mino.ValidLocation(false) {
|
||
|
board.currentMino = mino
|
||
|
board.StartLockDelayIfBottom()
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (board *Board) MinoRotateLeft() {
|
||
|
board.dropDistance = 0
|
||
|
mino := board.currentMino.CloneRotateLeft()
|
||
|
if mino.ValidLocation(false) {
|
||
|
board.currentMino = mino
|
||
|
board.StartLockDelayIfBottom()
|
||
|
return
|
||
|
}
|
||
|
mino.MoveLeft()
|
||
|
if mino.ValidLocation(false) {
|
||
|
board.currentMino = mino
|
||
|
board.StartLockDelayIfBottom()
|
||
|
return
|
||
|
}
|
||
|
mino.MoveRight()
|
||
|
mino.MoveRight()
|
||
|
if mino.ValidLocation(false) {
|
||
|
board.currentMino = mino
|
||
|
board.StartLockDelayIfBottom()
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (board *Board) MinoMoveDown() {
|
||
|
mino := board.currentMino.CloneMoveDown()
|
||
|
if mino.ValidLocation(false) {
|
||
|
board.dropDistance = 0
|
||
|
board.currentMino = mino
|
||
|
if !board.StartLockDelayIfBottom() {
|
||
|
engine.ResetTimer(0)
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
if !board.currentMino.ValidLocation(true) {
|
||
|
engine.GameOver()
|
||
|
return
|
||
|
}
|
||
|
board.nextMino()
|
||
|
}
|
||
|
|
||
|
func (board *Board) MinoDrop() {
|
||
|
board.dropDistance = 0
|
||
|
mino := board.currentMino.CloneMoveDown()
|
||
|
for mino.ValidLocation(false) {
|
||
|
board.dropDistance++
|
||
|
mino.MoveDown()
|
||
|
}
|
||
|
for i := 0; i < board.dropDistance; i++ {
|
||
|
board.currentMino.MoveDown()
|
||
|
}
|
||
|
if !board.currentMino.ValidLocation(true) {
|
||
|
engine.GameOver()
|
||
|
return
|
||
|
}
|
||
|
if board.dropDistance < 1 {
|
||
|
return
|
||
|
}
|
||
|
if !board.StartLockDelayIfBottom() {
|
||
|
engine.ResetTimer(0)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (board *Board) StartLockDelayIfBottom() bool {
|
||
|
mino := board.currentMino.CloneMoveDown()
|
||
|
if mino.ValidLocation(false) {
|
||
|
return false
|
||
|
}
|
||
|
engine.ResetTimer(300 * time.Millisecond)
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
func (board *Board) nextMino() {
|
||
|
engine.AddScore(board.dropDistance)
|
||
|
|
||
|
board.currentMino.SetOnBoard()
|
||
|
|
||
|
board.deleteCheck()
|
||
|
|
||
|
if !board.previewMino.ValidLocation(false) {
|
||
|
board.previewMino.MoveUp()
|
||
|
if !board.previewMino.ValidLocation(false) {
|
||
|
engine.GameOver()
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
|
||
|
board.currentMino = board.previewMino
|
||
|
board.previewMino = NewMino()
|
||
|
engine.ResetAiTimer()
|
||
|
engine.ResetTimer(0)
|
||
|
}
|
||
|
|
||
|
func (board *Board) deleteCheck() {
|
||
|
lines := board.fullLines()
|
||
|
if len(lines) < 1 {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
view.ShowDeleteAnimation(lines)
|
||
|
for _, line := range lines {
|
||
|
board.deleteLine(line)
|
||
|
}
|
||
|
|
||
|
engine.AddDeleteLines(len(lines))
|
||
|
}
|
||
|
|
||
|
func (board *Board) fullLines() []int {
|
||
|
fullLines := make([]int, 0, 1)
|
||
|
for j := 0; j < boardHeight; j++ {
|
||
|
if board.isFullLine(j) {
|
||
|
fullLines = append(fullLines, j)
|
||
|
}
|
||
|
}
|
||
|
return fullLines
|
||
|
}
|
||
|
|
||
|
func (board *Board) isFullLine(j int) bool {
|
||
|
for i := 0; i < boardWidth; i++ {
|
||
|
if board.colors[i][j] == blankColor {
|
||
|
return false
|
||
|
}
|
||
|
}
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
func (board *Board) deleteLine(line int) {
|
||
|
for i := 0; i < boardWidth; i++ {
|
||
|
board.colors[i][line] = blankColor
|
||
|
}
|
||
|
for j := line; j > 0; j-- {
|
||
|
for i := 0; i < boardWidth; 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++ {
|
||
|
board.colors[i][0] = blankColor
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (board *Board) SetColor(x int, y int, color termbox.Attribute, rotation int) {
|
||
|
board.colors[x][y] = color
|
||
|
board.rotation[x][y] = rotation
|
||
|
}
|
||
|
|
||
|
func ValidBlockLocation(x int, y int, mustBeOnBoard bool) bool {
|
||
|
if x < 0 || x >= boardWidth || y >= boardHeight {
|
||
|
return false
|
||
|
}
|
||
|
if mustBeOnBoard {
|
||
|
if y < 0 {
|
||
|
return false
|
||
|
}
|
||
|
} else {
|
||
|
if y < -2 {
|
||
|
return false
|
||
|
}
|
||
|
}
|
||
|
if y > -1 {
|
||
|
if board.colors[x][y] != blankColor {
|
||
|
return false
|
||
|
}
|
||
|
}
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
func ValidDisplayLocation(x int, y int) bool {
|
||
|
return x >= 0 && x < boardWidth && y >= 0 && y < boardHeight
|
||
|
}
|
||
|
|
||
|
func (board *Board) DrawBoard() {
|
||
|
for i := 0; i < boardWidth; i++ {
|
||
|
for j := 0; j < boardHeight; j++ {
|
||
|
if board.colors[i][j] != blankColor {
|
||
|
view.DrawBlock(i, j, board.colors[i][j], board.rotation[i][j])
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (board *Board) DrawPreviewMino() {
|
||
|
board.previewMino.DrawMino(MinoPreview)
|
||
|
}
|
||
|
|
||
|
func (board *Board) DrawCurrentMino() {
|
||
|
board.currentMino.DrawMino(MinoCurrent)
|
||
|
}
|
||
|
|
||
|
func (board *Board) DrawDropMino() {
|
||
|
mino := board.currentMino.CloneMoveDown()
|
||
|
if !mino.ValidLocation(false) {
|
||
|
return
|
||
|
}
|
||
|
for mino.ValidLocation(false) {
|
||
|
mino.MoveDown()
|
||
|
}
|
||
|
mino.MoveUp()
|
||
|
mino.DrawMino(MinoDrop)
|
||
|
}
|
||
|
|
||
|
// for debuging
|
||
|
func (board *Board) drawDebugBoard() {
|
||
|
for j := 0; j < boardHeight; j++ {
|
||
|
for i := 0; i < boardWidth; i++ {
|
||
|
switch board.colors[i][j] {
|
||
|
case blankColor:
|
||
|
fmt.Print(".")
|
||
|
case termbox.ColorBlue:
|
||
|
fmt.Print("B")
|
||
|
case termbox.ColorCyan:
|
||
|
fmt.Print("C")
|
||
|
case termbox.ColorGreen:
|
||
|
fmt.Print("G")
|
||
|
case termbox.ColorMagenta:
|
||
|
fmt.Print("M")
|
||
|
case termbox.ColorRed:
|
||
|
fmt.Print("R")
|
||
|
case termbox.ColorWhite:
|
||
|
fmt.Print("W")
|
||
|
case termbox.ColorYellow:
|
||
|
fmt.Print("Y")
|
||
|
}
|
||
|
}
|
||
|
fmt.Println("")
|
||
|
}
|
||
|
}
|