go-tetris/engine.go

312 lines
5.9 KiB
Go
Raw Permalink Normal View History

2017-03-27 15:07:29 -05:00
package main
import (
"time"
2019-12-01 15:03:27 -06:00
"github.com/gdamore/tcell"
)
2017-03-27 15:07:29 -05:00
2019-12-01 15:03:27 -06:00
// EventEngineStopRun stop the run of the engine
type EventEngineStopRun struct {
EventGame
}
2018-10-02 20:21:08 -05:00
// NewEngine creates new engine
func NewEngine() {
engine = &Engine{
2019-12-01 15:03:27 -06:00
chanStop: make(chan struct{}),
chanEventKey: make(chan *tcell.EventKey, 8),
mode: engineModeGameOver,
tickTime: time.Hour,
ranking: NewRanking(),
ai: NewAi(),
2017-03-27 15:07:29 -05:00
}
2019-12-01 15:03:27 -06:00
board.Clear()
go engine.Run()
2017-03-27 15:07:29 -05:00
}
2018-10-02 20:21:08 -05:00
// Run runs the engine
2017-03-27 15:07:29 -05:00
func (engine *Engine) Run() {
2018-06-01 10:16:36 -05:00
logger.Println("Engine Run start")
2017-03-27 15:07:29 -05:00
2019-12-01 15:03:27 -06:00
var event tcell.Event
loop:
for {
event = screen.PollEvent()
switch eventType := event.(type) {
case *tcell.EventKey:
select {
case engine.chanEventKey <- eventType:
default:
}
case *EventEngineStopRun:
break loop
case *tcell.EventResize:
view.RefreshScreen()
default:
logger.Printf("event type %T", eventType)
}
}
logger.Println("Engine Run end")
}
// Start the game
func (engine *Engine) Start() {
logger.Println("Engine Start start")
2017-03-27 15:07:29 -05:00
engine.timer = time.NewTimer(engine.tickTime)
engine.timer.Stop()
engine.aiTimer = time.NewTimer(engine.tickTime)
engine.aiTimer.Stop()
view.RefreshScreen()
2019-12-01 15:03:27 -06:00
var eventKey *tcell.EventKey
2017-03-27 15:07:29 -05:00
loop:
for {
select {
case <-engine.chanStop:
break loop
default:
select {
2019-12-01 15:03:27 -06:00
case eventKey = <-engine.chanEventKey:
engine.ProcessEventKey(eventKey)
2017-03-27 15:07:29 -05:00
view.RefreshScreen()
case <-engine.timer.C:
engine.tick()
case <-engine.aiTimer.C:
engine.ai.ProcessQueue()
2019-01-09 20:30:45 -06:00
engine.aiTimer.Reset(engine.tickTime / aiTickDivider)
2017-03-27 15:07:29 -05:00
case <-engine.chanStop:
break loop
}
}
}
2019-12-01 15:03:27 -06:00
screen.PostEventWait(&EventEngineStopRun{})
logger.Println("Engine Start end")
2017-03-27 15:07:29 -05:00
}
2019-12-01 15:03:27 -06:00
// Stop the game
2017-03-27 15:07:29 -05:00
func (engine *Engine) Stop() {
2018-06-01 10:16:36 -05:00
logger.Println("Engine Stop start")
2017-03-27 15:07:29 -05:00
if !engine.stopped {
engine.stopped = true
2019-12-01 15:03:27 -06:00
engine.mode = engineModeStopped
2017-03-27 15:07:29 -05:00
close(engine.chanStop)
}
engine.timer.Stop()
engine.aiTimer.Stop()
2018-06-01 10:16:36 -05:00
logger.Println("Engine Stop end")
2017-03-27 15:07:29 -05:00
}
2019-12-01 15:03:27 -06:00
// Pause the game
2017-03-27 15:07:29 -05:00
func (engine *Engine) Pause() {
if !engine.timer.Stop() {
select {
case <-engine.timer.C:
default:
}
}
if !engine.aiTimer.Stop() {
select {
case <-engine.aiTimer.C:
default:
}
}
2019-12-01 15:03:27 -06:00
engine.mode = engineModePaused
2017-03-27 15:07:29 -05:00
}
2019-12-01 15:03:27 -06:00
// UnPause the game
2017-03-27 15:07:29 -05:00
func (engine *Engine) UnPause() {
engine.timer.Reset(engine.tickTime)
if engine.aiEnabled {
2019-01-09 20:30:45 -06:00
engine.aiTimer.Reset(engine.tickTime / aiTickDivider)
2019-12-01 15:03:27 -06:00
engine.mode = engineModeRunWithAI
} else {
engine.mode = engineModeRun
2017-03-27 15:07:29 -05:00
}
}
2018-10-02 20:21:08 -05:00
// PreviewBoard sets previewBoard to true
func (engine *Engine) PreviewBoard() {
2019-12-01 15:03:27 -06:00
engine.mode = engineModePreview
}
2018-10-02 20:21:08 -05:00
// NewGame resets board and starts a new game
2017-03-27 15:07:29 -05:00
func (engine *Engine) NewGame() {
2018-06-01 10:16:36 -05:00
logger.Println("Engine NewGame start")
2017-03-27 15:07:29 -05:00
board.Clear()
2017-03-27 15:07:29 -05:00
engine.tickTime = 480 * time.Millisecond
engine.score = 0
engine.level = 1
engine.deleteLines = 0
loop:
for {
select {
2019-12-01 15:03:27 -06:00
case <-engine.chanEventKey:
2017-03-27 15:07:29 -05:00
default:
break loop
}
}
if engine.aiEnabled {
engine.ai.GetBestQueue()
2019-12-01 15:03:27 -06:00
engine.mode = engineModeRunWithAI
} else {
engine.mode = engineModeRun
2017-03-27 15:07:29 -05:00
}
engine.UnPause()
2018-06-01 10:16:36 -05:00
logger.Println("Engine NewGame end")
2017-03-27 15:07:29 -05:00
}
2018-10-02 20:21:08 -05:00
// ResetTimer resets the time for lock delay or tick time
2017-03-27 15:07:29 -05:00
func (engine *Engine) ResetTimer(duration time.Duration) {
if !engine.timer.Stop() {
select {
case <-engine.timer.C:
default:
}
}
if duration == 0 {
// duration 0 means tick time
engine.timer.Reset(engine.tickTime)
} else {
// duration is lock delay
engine.timer.Reset(duration)
}
}
2018-10-02 20:21:08 -05:00
// AiGetBestQueue calls AI to get best queue
func (engine *Engine) AiGetBestQueue() {
2017-03-27 15:07:29 -05:00
if !engine.aiEnabled {
return
}
go engine.ai.GetBestQueue()
2017-03-27 15:07:29 -05:00
}
2018-10-02 20:21:08 -05:00
// tick move mino down and refreshes screen
2017-03-27 15:07:29 -05:00
func (engine *Engine) tick() {
board.MinoMoveDown()
view.RefreshScreen()
}
2018-10-02 20:21:08 -05:00
// AddDeleteLines adds deleted lines to score
2017-03-27 15:07:29 -05:00
func (engine *Engine) AddDeleteLines(lines int) {
engine.deleteLines += lines
if engine.deleteLines > 999999 {
engine.deleteLines = 999999
}
switch lines {
case 1:
engine.AddScore(40 * (engine.level + 1))
case 2:
engine.AddScore(100 * (engine.level + 1))
case 3:
engine.AddScore(300 * (engine.level + 1))
case 4:
engine.AddScore(1200 * (engine.level + 1))
}
if engine.level < engine.deleteLines/10 {
engine.LevelUp()
}
}
2018-10-02 20:21:08 -05:00
// AddScore adds to score
2017-03-27 15:07:29 -05:00
func (engine *Engine) AddScore(add int) {
engine.score += add
if engine.score > 9999999 {
engine.score = 9999999
2017-03-27 15:07:29 -05:00
}
}
2018-10-02 20:21:08 -05:00
// LevelUp goes up a level
2017-03-27 15:07:29 -05:00
func (engine *Engine) LevelUp() {
if engine.level >= 30 {
return
}
engine.level++
switch {
case engine.level > 29:
engine.tickTime = 10 * time.Millisecond
case engine.level > 25:
engine.tickTime = 20 * time.Millisecond
case engine.level > 19:
// 50 to 30
engine.tickTime = time.Duration(10*(15-engine.level/2)) * time.Millisecond
case engine.level > 9:
// 150 to 60
engine.tickTime = time.Duration(10*(25-engine.level)) * time.Millisecond
default:
// 480 to 160
engine.tickTime = time.Duration(10*(52-4*engine.level)) * time.Millisecond
}
}
2018-10-02 20:21:08 -05:00
// GameOver pauses engine and sets to game over
2017-03-27 15:07:29 -05:00
func (engine *Engine) GameOver() {
2018-06-01 10:16:36 -05:00
logger.Println("Engine GameOver start")
2017-03-27 15:07:29 -05:00
engine.Pause()
2019-12-01 15:03:27 -06:00
engine.mode = engineModeGameOver
2017-03-27 15:07:29 -05:00
view.ShowGameOverAnimation()
2017-03-27 15:07:29 -05:00
loop:
for {
select {
2019-12-01 15:03:27 -06:00
case <-engine.chanEventKey:
2017-03-27 15:07:29 -05:00
default:
break loop
}
}
engine.ranking.InsertScore(uint64(engine.score))
engine.ranking.Save()
2018-06-01 10:16:36 -05:00
logger.Println("Engine GameOver end")
2017-03-27 15:07:29 -05:00
}
2018-10-02 20:21:08 -05:00
// EnabledAi enables the AI
2017-03-27 15:07:29 -05:00
func (engine *Engine) EnabledAi() {
engine.aiEnabled = true
go engine.ai.GetBestQueue()
2019-01-09 20:30:45 -06:00
engine.aiTimer.Reset(engine.tickTime / aiTickDivider)
2017-03-27 15:07:29 -05:00
}
2018-10-02 20:21:08 -05:00
// DisableAi disables the AI
2017-03-27 15:07:29 -05:00
func (engine *Engine) DisableAi() {
engine.aiEnabled = false
2019-12-01 15:03:27 -06:00
engine.mode = engineModeRun
2017-03-27 15:07:29 -05:00
if !engine.aiTimer.Stop() {
select {
case <-engine.aiTimer.C:
default:
}
}
}
2019-01-09 20:30:45 -06:00
// EnabledEditMode enables edit mode
func (engine *Engine) EnabledEditMode() {
edit.EnabledEditMode()
2019-12-01 15:03:27 -06:00
engine.mode = engineModeEdit
2019-01-09 20:30:45 -06:00
}
// DisableEditMode disables edit mode
func (engine *Engine) DisableEditMode() {
edit.DisableEditMode()
2019-12-01 15:03:27 -06:00
engine.mode = engineModePreview
2019-01-09 20:30:45 -06:00
}