Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package main
- import (
- "bufio"
- "bytes"
- "fmt"
- "log"
- "math"
- "net"
- "regexp"
- "strconv"
- "time"
- )
- const (
- SERVER_USER = "100 LOGIN\r\n" // Výzva k zadání uživatelského jména
- SERVER_PASSWORD = "101 PASSWORD\r\n" // Výzva k zadání uživatelského hesla
- SERVER_MOVE = "102 MOVE\r\n" // Příkaz pro pohyb o jedno pole vpřed
- SERVER_TURN_LEFT = "103 TURN LEFT\r\n" // Příkaz pro otočení doleva
- SERVER_TURN_RIGHT = "104 TURN RIGHT\r\n" // Příkaz pro otočení doprava
- SERVER_PICK_UP = "105 GET MESSAGE\r\n" // Příkaz pro vyzvednutí zprávy
- SERVER_OK = "200 OK\r\n" // Kladné potvrzení
- SERVER_LOGIN_FAILED = "300 LOGIN FAILED\r\n" // Chybné heslo
- SERVER_SYNTAX_ERROR = "301 SYNTAX ERROR\r\n" // Chybná syntaxe zprávy
- SERVER_LOGIC_ERROR = "302 LOGIC ERROR\r\n" // Zpráva odeslaná ve špatné situaci
- )
- const (
- TIMEOUT = 1
- TIMEOUT_RECHARGING = 5
- )
- var (
- CLIENT_PASSWORD = regexp.MustCompile(`^[1-9][0-9]{0,4}\r\n$`)
- CLIENT_CONFIRM = regexp.MustCompile(`^OK -?[0-9]+ -?[0-9]+\r\n$`)
- CLIENT_RECHARGING = regexp.MustCompile(`^RECHARGING\r\n$`)
- CLIENT_FULL_POWER = regexp.MustCompile(`^FULL POWER\r\n$`)
- )
- type Bot struct {
- *net.TCPConn
- *bufio.Reader
- recharging bool
- posX, posY int
- prevX, prevY int
- dirX, dirY int
- }
- func NewBot(conn *net.TCPConn) *Bot {
- log.Println("NEW BOT :: ", conn.RemoteAddr())
- b := new(Bot)
- b.TCPConn = conn
- b.Reader = bufio.NewReader(conn)
- b.prevX, b.prevY = math.MaxInt64, math.MaxInt64
- return b
- }
- func (b *Bot) Auth() {
- b.SendMessage(SERVER_USER)
- username := b.ReceiveMessage()
- b.SendMessage(SERVER_PASSWORD)
- password := b.ReceiveMessage()
- if !CLIENT_PASSWORD.MatchString(password) {
- panic(SERVER_SYNTAX_ERROR)
- }
- checkSum := 0
- for _, v := range username[:len(username)-2] {
- checkSum += int(v)
- }
- pass, err := strconv.Atoi(password[:len(password)-2])
- if err != nil {
- panic(SERVER_SYNTAX_ERROR)
- }
- if checkSum != pass {
- panic(SERVER_LOGIN_FAILED)
- }
- }
- func (b *Bot) Navigate() {
- b.SendMessage(SERVER_TURN_LEFT) // initial move to get bots position
- for {
- msg := b.ReceiveMessage()
- if CLIENT_CONFIRM.MatchString(msg) {
- b.CheckCoords(msg)
- } else {
- panic(SERVER_SYNTAX_ERROR)
- }
- if b.posX == 0 && b.posY == 0 {
- log.Println("Bot is on the [0:0] coords")
- b.SendMessage(SERVER_PICK_UP)
- msg := b.ReceiveMessage()
- fmt.Print("Secret message: ", msg)
- b.SendMessage(SERVER_OK)
- return
- } else {
- if b.dirX == 0 && b.dirY == 0 {
- b.SendMessage(SERVER_MOVE) // initial move to get direction of bot
- } else {
- if math.Abs(float64(b.posX+b.dirX)) < math.Abs(float64(b.posX)) { // if bot moves it moves to closer position
- b.SendMessage(SERVER_MOVE)
- } else if math.Abs(float64(b.posY+b.dirY)) < math.Abs(float64(b.posY)) { // if bot moves it moves to closer position
- b.SendMessage(SERVER_MOVE)
- } else if b.posX == 0 {
- if (b.posY > 0 && b.dirX == -1) || (b.posY < 0 && b.dirX == 1) { // bot in top-right or bottom-left quadrant
- b.SendMessage(SERVER_TURN_LEFT)
- } else if (b.posY > 0 && b.dirX == 1) || (b.posY < 0 && b.dirX == -1) { // bot in top-left or bottom-right quadrant
- b.SendMessage(SERVER_TURN_RIGHT)
- }
- } else {
- b.SendMessage(SERVER_TURN_LEFT) // bot in bad position. try turning left
- }
- }
- }
- }
- }
- func (b *Bot) CheckCoords(msg string) {
- if b.prevX != math.MaxInt64 && b.prevY != math.MaxInt64 {
- b.prevX, b.prevY = b.posX, b.posY
- }
- _, err := fmt.Sscanf(msg, "OK %d %d\r\n", &b.posX, &b.posY)
- if err != nil {
- panic(SERVER_SYNTAX_ERROR)
- }
- if b.prevX == math.MaxInt64 && b.prevY == math.MaxInt64 {
- b.prevX, b.prevY = b.posX, b.posY
- }
- b.dirX = b.posX - b.prevX
- b.dirY = b.posY - b.prevY
- }
- func (b *Bot) ReceiveMessage() string {
- var buf bytes.Buffer
- isR := false
- for {
- data, err := b.ReadByte()
- if err != nil {
- panic(SERVER_SYNTAX_ERROR)
- }
- b.TCPConn.SetDeadline(time.Now().Add(TIMEOUT * time.Second))
- buf.WriteByte(data)
- if data == '\n' && isR {
- break
- }
- if buf.Len() == 100 {
- panic(SERVER_SYNTAX_ERROR)
- }
- // jesus man WTF :O
- if len(buf.String()) > 2 && buf.String()[:2] == "OK" && isR && data == '\r' {
- panic(SERVER_SYNTAX_ERROR)
- }
- isR = data == '\r'
- }
- msg := buf.String()
- log.Printf("RECV :: %#v", msg)
- if CLIENT_RECHARGING.MatchString(msg) {
- b.recharging = true
- b.TCPConn.SetDeadline(time.Now().Add(TIMEOUT_RECHARGING * time.Second))
- str := b.ReceiveMessage()
- if CLIENT_FULL_POWER.MatchString(str) {
- if b.recharging == false {
- panic(SERVER_LOGIC_ERROR)
- }
- } else {
- panic(SERVER_LOGIC_ERROR)
- }
- msg = b.ReceiveMessage()
- }
- return msg
- }
- func (b *Bot) SendMessage(msg string) {
- log.Printf("SEND :: %#v", msg)
- fmt.Fprint(b, msg)
- b.SetDeadline(time.Now().Add(TIMEOUT * time.Second))
- }
- func (b *Bot) Run() {
- b.Auth()
- b.SendMessage(SERVER_OK)
- b.Navigate()
- }
- func main() {
- address, _ := net.ResolveTCPAddr("tcp", ":3999")
- listener, _ := net.ListenTCP("tcp", address)
- for {
- conn, _ := listener.AcceptTCP()
- go func(c *net.TCPConn) {
- log.Println("ACCEPT :: ", c.RemoteAddr())
- defer func() {
- err := recover()
- switch err.(type) {
- case string:
- log.Print("PANIC :: ", err.(string))
- fmt.Fprint(c, err.(string))
- case nil:
- log.Println("BOT SUCCESSFUL")
- }
- log.Println("CLOSE :: ", c.RemoteAddr())
- c.Close()
- }()
- b := NewBot(c)
- b.Run()
- }(conn)
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement