⚠️ Warning: This is a draft ⚠️

This means it might contain formatting issues, incorrect code, conceptual problems, or other severe issues.

If you want to help to improve and eventually enable this page, please fork RosettaGit's repository and open a merge request on GitHub.

==Code== {{trans|C++}} {{libheader|termbox-go}} {{works with|Ubuntu 16.04}}

This hasn't been tested on Windows 10 but should work.

Note that this version uses the Z key (rather than the Y key) to move diagonally downwards to the left and the H key (rather than the Z key) to wait for the end. A leave key, L, has also been added in case one wants to end the game immediately.

package main

import (
    "fmt"
    "github.com/nsf/termbox-go"
    "log"
    "math/rand"
    "time"
)

type coord struct{ x, y int }

const (
    width  = 62
    height = 42
    inc    = 10
)

var (
    board       [width * height]rune
    robotsCount = 0
    score       = 0
    aliveRobots = 0
    bold        = termbox.AttrBold
    cursor      coord
    alive       bool
)

var colors = [10]termbox.Attribute{
    termbox.ColorDefault,
    termbox.ColorWhite,
    termbox.ColorBlack | bold,
    termbox.ColorBlue | bold,
    termbox.ColorGreen | bold,
    termbox.ColorCyan | bold,
    termbox.ColorRed | bold,
    termbox.ColorMagenta | bold,
    termbox.ColorYellow | bold,
    termbox.ColorWhite | bold,
}

func printAt(x, y int, s string, fg, bg termbox.Attribute) {
    for _, r := range s {
        termbox.SetCell(x, y, r, fg, bg)
        x++
    }
}

func clearBoard() {
    for y := 0; y < height; y++ {
        for x := 0; x < width; x++ {
            board[x+width*y] = 32
            if x == 0 || x == width-1 || y == 0 || y == height-1 {
                board[x+width*y] = '#'
            }
        }
    }
}

func createBoard() {
    aliveRobots = robotsCount
    for x := 0; x < robotsCount; x++ {
        var a, b int
        for {
            a = rand.Intn(width)
            b = rand.Intn(height)
            if board[a+width*b] == 32 {
                break
            }
        }
        board[a+width*b] = '+'
    }
    printScore()
}

func displayBoard() {
    var fg termbox.Attribute
    bg := colors[0]
    for y := 0; y < height; y++ {
        for x := 0; x < width; x++ {
            t := board[x+width*y]
            switch t {
            case ' ':
                fg = colors[0]
            case '#':
                fg = colors[3]
            case '+':
                fg = colors[8]
            case 'Å', '*':
                fg = colors[6]
            case '@':
                fg = colors[4]
            }
            printAt(x, y, string(t), fg, bg)
        }
    }
    termbox.Flush()
}

func teleport() {
    board[cursor.x+width*cursor.y] = 32
    cursor.x = rand.Intn(width-2) + 1
    cursor.y = rand.Intn(height-2) + 1
    x := cursor.x + width*cursor.y
    if board[x] == '*' || board[x] == '+' || board[x] == '~' {
        alive = false
        board[x] = 'Å'
    } else {
        board[x] = '@'
    }
}

func printScore() {
    fg := colors[4]
    bg := termbox.ColorGreen
    s := fmt.Sprintf("      SCORE: %d      ", score)
    printAt(0, height, s, fg, bg)
    termbox.Flush()
}

func execute(x, y int) {
    board[cursor.x+width*cursor.y] = 32
    cursor.x += x
    cursor.y += y
    board[cursor.x+width*cursor.y] = '@'
    moveRobots()
}

func waitForEnd() {
    for aliveRobots != 0 && alive {
        moveRobots()
        displayBoard()
        time.Sleep(500 * time.Millisecond)
    }
}

func moveRobots() {
    for y := 0; y < height; y++ {
        for x := 0; x < width; x++ {
            if board[x+width*y] != '+' {
                continue
            }
            tx, ty := x, y
            if tx < cursor.x {
                tx++
            } else if tx > cursor.x {
                tx--
            }
            if ty < cursor.y {
                ty++
            } else if ty > cursor.y {
                ty--
            }
            if tx != x || ty != y {
                board[x+width*y] = 32
                if board[tx+width*ty] == 32 {
                    board[tx+width*ty] = '~'
                } else {
                    checkCollision(tx, ty)
                }
            }
        }
    }
    for x := 0; x < width*height; x++ {
        if board[x] == '~' {
            board[x] = '+'
        }
    }
}

func checkCollision(x, y int) {
    if cursor.x == x && cursor.y == y {
        alive = false
        board[x+width*y] = 'Å'
        return
    }
    x += y * width
    if board[x] == '*' || board[x] == '+' || board[x] == '~' {
        if board[x] != '*' {
            aliveRobots--
            score++
        }
        board[x] = '*'
        aliveRobots--
        score++
    }
}

func check(err error) {
    if err != nil {
        log.Fatal(err)
    }
}

func main() {
    rand.Seed(time.Now().UnixNano())
    err := termbox.Init()
    check(err)
    defer termbox.Close()

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

    for {
        termbox.HideCursor()
        robotsCount = 10
        score = 0
        alive = true
        clearBoard()
        cursor.x = rand.Intn(width-2) + 1
        cursor.y = rand.Intn(height-2) + 1
        board[cursor.x+width*cursor.y] = '@'
        createBoard()
        for {
            displayBoard()
            select {
            case ev := <-eventQueue:
                if ev.Type == termbox.EventKey {
                    switch ev.Ch {
                    case 'q', 'Q':
                        if cursor.x > 1 && cursor.y > 1 {
                            execute(-1, -1)
                        }
                    case 'w', 'W':
                        if cursor.y > 1 {
                            execute(0, -1)
                        }
                    case 'e', 'E':
                        if cursor.x < width-2 && cursor.y > 1 {
                            execute(1, -1)
                        }
                    case 'a', 'A':
                        if cursor.x > 1 {
                            execute(-1, 0)
                        }
                    case 'd', 'D':
                        if cursor.x < width-2 {
                            execute(1, 0)
                        }
                    case 'z', 'Z':
                        if cursor.x > 1 && cursor.y < height-2 {
                            execute(-1, 1)
                        }
                    case 'x', 'X':
                        if cursor.y < height-2 {
                            execute(0, 1)
                        }
                    case 'c', 'C':
                        if cursor.x < width-2 && cursor.y < height-2 {
                            execute(1, 1)
                        }
                    case 't', 'T':
                        teleport()
                        moveRobots()
                    case 'h', 'H':
                        waitForEnd()
                    case 'l', 'L': // leave key
                        return
                    }
                } else if ev.Type == termbox.EventResize {
                    termbox.Flush()
                }
            }
            printScore()
            if aliveRobots == 0 {
                robotsCount += inc
                clearBoard()
                board[cursor.x+width*cursor.y] = '@'
                createBoard()
            }
            if !alive {
                break
            }
        }
        displayBoard()
        fg := colors[7]
        bg := colors[0]
        printAt(10, 8, "+----------------------------------------+", fg, bg)
        printAt(10, 9, "|               GAME OVER                |", fg, bg)
        printAt(10, 10, "|            PLAY AGAIN(Y/N)?            |", fg, bg)
        printAt(10, 11, "+----------------------------------------+", fg, bg)
        termbox.SetCursor(39, 10)
        termbox.Flush()
        select {
        case ev := <-eventQueue:
            if ev.Type == termbox.EventKey {
                if ev.Ch == 'y' || ev.Ch == 'Y' {
                    break
                } else {
                    return
                }
            }
        }
    }
}