package main import ( "fmt" "github.com/pkg/term" ) type PieceType int const ( IPiece PieceType = iota JPiece LPiece SPiece ZPiece TPiece OPiece ) type Point struct { X, Y int } type Piece struct { Type PieceType RelX int RelY int Layout []Point Lock int } type Bag []Piece type Field [20][10]bool func (f Field) String() (output string) { var toprow [10]bool var top bool for _, row := range f { top = !top for i, block := range row { if top { toprow[i] = block continue } switch { case toprow[i] && block: output += "\u2588" case toprow[i] && !block: output += "\u2580" case !toprow[i] && block: output += "\u2584" default: output += " " } } if !top { output += "\n" } } return output } // GetKey() returns the key currently pressed. It always returns a 3 byte slice. Check first element for Escape for handling arrow keys // Because a defer would trigger too late and the Restore and Close are essential, separated in a function. func GetKey() []byte { t, _ := term.Open("/dev/tty") term.RawMode(t) key := make([]byte, 3) t.Read(key) t.Restore() t.Close() return key } func main() { var f Field fmt.Print("\033[2J") // Clear screen p := Point{} var oldp Point for { fmt.Print("\033[2J") // Clear screen f[oldp.Y][oldp.X] = false oldp = p f[p.Y][p.X] = true fmt.Print("\033[0;0H") // Position to 0,0 fmt.Println(f.String()) key := GetKey() switch key[0] { case 27: // Escape, read the arrow key pressed switch key[2] { case 65: // Up p.Y = (p.Y + 20 - 1)%20 case 66: // Down p.Y = (p.Y + 20 + 1)%20 case 67: // Right p.X = (p.X + 10 + 1)%10 case 68: // Left p.X = (p.X + 10 - 1)%10 default: fmt.Println("...escape, escape!") return } case 'q': fmt.Println("...that was exciting!") return default: if key[0] != 0 { fmt.Print(string(key[0])) } } } }