Console Tetris 만들기 (1)

사이드 프로잭트로 console에 테트리스를 만드는 시간을 가지고 있습니다. 이 편은 3~5편 사이로 예상하고 있으며, 코드가 구현될 때마다 분류하여 정리해서 올려보도록 하겠습니다. 1편은 키보드 입력을 받는 부분을 만들어 보겠습니다. console 라이브러리중에 콘솔에 색깔을 출력하고, 키보드 입력을 받는 termbox-go를 통해서 만들어 보도록 하겠습니다.

1편 요약

이번 편에는 입력을 받고, 입력을 수행하는 스레드가 두개가 필요하여 시분할 처리를 수행하는 고루틴을 통해서 만들겠습니다.

먼저, 입력을 받는 go routine 1, 입력을 받아서 명령을 수행하는 go routine 2, 를 만들어서 수행하도록
할 것 입니다. 먼저 go routine1을 만들것 입니다.

go routine1

고루틴 시작전에 sync로 go routine이 main 함수보다 늦게
끝날 것을 고려해 설정해야하기 떄문에 wait.Add(2)
메인 함수가 기달려달라고 설정해야합니다.


// sync wait 버전을 만듭니다.
var wait sync.WaitGroup
wait.Add(2)


// termbox 초기 시작
err := termbox.Init()
if err != nil {
    panic(err)
}
defer termbox.Close()

// termbox event Queue, go routine1 생성
// 이벤트를 지속적으로 받아옵니다.
eventQueue := make(chan termbox.Event)
go func() {
    for {
        defer wait.Done()
        eventQueue <- termbox.PollEvent()
    }
}()

go routine2

고루틴 2는 앞서 만든 eventQueue를 통해서, 받고 그 Type에 따라서 명령어 타임을 진행해주면 됩니다.
그 과정에서 go-routine으로 받은 값이기 떄문에, select가 필요합니다.

// goroutine2 생성합니다.
go func() {
    for {
        // 채널을 통해서 받아오므로 select문 
        select {
        case qu := <- eventQueue:

            // Type에 따라서 분류하여 작동
            if qu.Type == termbox.EventKey {
                switch {
                case qu.Key == termbox.KeyArrowLeft:
                    fmt.Println("left")
                case qu.Key == termbox.KeyArrowRight:
                    fmt.Println("right")
                case qu.Key == termbox.KeyArrowUp:
                    fmt.Println("up")
                case qu.Key == termbox.ArrowDown:
                    fmt.Println("down")
                case qu.Key == termbox.KeySpace:
                    fmt.Println("space")
                case qu.Key == termbox.KeyEsc:
                    wait.Done()
                }
            }
        default:
            time.Sleep(tetrisSpeed)
        }
    }
}()
wait

전체코드

package main

import (
    "fmt"
    "sync"
    "time"

    "github.com/nsf/termbox-go"
)

const tetirisSpeed = 10 * time.Millisecond

func main() {
    var wait sync.WaitGroup
    wait.Add(2)

    err := termbox.Init()
    if err != nil {
        panic(err)
    }
    defer termbox.Close()

    eventQueue := make(chan termbox.Event)
    go func() {
        for {
            eventQueue <- termbox.PollEvent()
        }
    }()

    go func() {
        for {
        	// go routine에 의해서, switch문을 select로 대체
            select {
           
            case qu := <-eventQueue:
            	// Type에 따라서 분류
                if qu.Type == termbox.EventKey {
                    switch {
                    case qu.Key == termbox.KeyArrowLeft:
                        fmt.Println("left")
                    case qu.Key == termbox.KeyArrowRight:
                        fmt.Println("right")
                    case qu.Key == termbox.KeyArrowUp:
                        fmt.Println("up")
                    case qu.Key == termbox.KeySpace:
                        fmt.Println("space")
                    case qu.Key == termbox.KeyArrowDown:
                        fmt.Println("down")
                    case qu.Key == termbox.KeyEsc:
                        fmt.Println("done")
                        wait.Done()
                        wait.Done()
                    }
                }
            default:
                time.Sleep(tetrisSpeed)
            }
        }
    }()
    // go routine 끝날 떄까지, 기다리기
    wait.Wait()
}

이렇게 하면, 종료키, 위, 아래, 스페이스, 오른쪽, 왼쪽 키가 정상적으로 입력되는 것을 확인할 수 있다.

tetrisSpeed는 블락이 떨어지는 속도를 의미합니다. 이것을 통해서 난이도를 변경하거나 할 수 있을 것 입니다.

입력 받기 성공

다음 편에는 golang 본판을 짜보는 시간을 가지겠습니다.

- github code

https://github.com/woong-s/console_go_tetris/commit/4641bcb0a3ea21ab810970e428fb7131e55d2279

'언어 > GO' 카테고리의 다른 글

GO - errors new 에러 핸들링  (0) 2021.11.30