Robots/Go

From Rosetta Code
Revision as of 19:00, 23 April 2019 by PureFox (talk | contribs) (→‎{{header|Go}}: Changed header to 'Code'.)

Code

Translation of: C++
Library: 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. <lang go>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
               }
           }
       }
   }

}</lang>