Task: Remote agent_Simulation




Go: package world

import (
    "bytes"
    "fmt"
    "log"

    "ra/ifc"
)


















var maze = []byte(`
WWWWWWWWWWWWWWWW 
W     W        W 
W     W        W 
W  Rb W  Rg B  W 
W              W 
W              W 
W  G  G  B  G  W 
W              W 
W              W 
W  Br G  W  R  W 
W        W  ^  W 
W        W     W 
WWWWWWWWWWWWWWWW`)



var (
    stream   ifc.Streamer
    rowLen   int
    agentPos int
)





const dirString = "^>v<"

var directions = []byte(dirString)

func rightOf(dir byte) byte {
    return directions[(bytes.IndexByte(directions, dir)+1)%4]
}

func leftOf(dir byte) byte {
    return directions[(bytes.IndexByte(directions, dir)+3)%4]
}

func World(s ifc.Streamer) {
    stream = s
    rowLen = bytes.Index(maze[1:], []byte{'\n'}) + 1
    
    
    
    cols := rowLen / 3
    rows := ((len(maze)+1)/rowLen + 2) / 3
    if len(maze) != (rows*3-2)*cols*3-1 {
        log.Fatal("mis-shaped maze")
    }
    agentPos = bytes.IndexAny(maze, dirString)
    if agentPos < 0 {
        log.Fatal("agent not in maze")
    }
    
    time := 0
    logTime(time)
    
    stream.Send(ifc.Handshake)
    hs := stream.Rec()
    if hs != ifc.Handshake {
        log.Fatal("world: thats no handshake.")
    }
    
    log.Print(string(maze))
    
    gameOver := false
    timeConsumed := 0
    for !gameOver {
        gameOver, timeConsumed = process(stream.Rec())
        time += timeConsumed
        logTime(time)
        log.Print(string(maze))
    }
}



func logTime(t int) {
    log.SetPrefix(fmt.Sprintf("%06d: ", t))
}


func process(cmd byte) (gameOver bool, timeConsumed int) {
    
    timeConsumed = 1
    switch cmd {
    case ifc.CmdForward:
        timeConsumed = forward()
    case ifc.CmdRight:
        right()
    case ifc.CmdLeft:
        left()
    case ifc.CmdGet:
        get()
    case ifc.CmdDrop:
        
        gameOver = drop()
    }
    
    stream.Send(ifc.EvStop)
    return
}   
    
func forward() (timeConsumed int) {
    sectorOrigin := agentPos - rowLen
    switch maze[agentPos] {
    case '^':
        sectorOrigin -= 3 * rowLen
    case 'v':
        sectorOrigin += 3 * rowLen
    case '<':
        sectorOrigin -= 3
    case '>':
        sectorOrigin += 3
    }
    if maze[sectorOrigin] == 'W' {
        stream.Send(ifc.EvBump)
        
        return 0
    }
    
    newPos := sectorOrigin + rowLen
    maze[newPos] = maze[agentPos]
    maze[newPos+1] = maze[agentPos+1]
    maze[agentPos] = ' '
    maze[agentPos+1] = ' '
    agentPos = newPos
    
    stream.Send(maze[sectorOrigin])
    if ball := maze[sectorOrigin+1]; ball != ' ' {
        
        stream.Send(maze[sectorOrigin+1])
    }
    
    return 1
}

func right() {
    maze[agentPos] = rightOf(maze[agentPos])
}

func left() {
    maze[agentPos] = leftOf(maze[agentPos])
}

func get() {
    agentBall := agentPos + 1
    sectorBall := agentBall - rowLen
    can := true
    if maze[sectorBall] == ' ' {
        stream.Send(ifc.EvNoBallInSector)
        can = false
    }
    if maze[agentBall] != ' ' {
        stream.Send(ifc.EvAgentFull)
        can = false
    }
    if can {
        maze[agentBall] = maze[sectorBall]
        maze[sectorBall] = ' '
    }
}

func drop() (gameOver bool) {
    agentBall := agentPos + 1
    sectorBall := agentBall - rowLen
    can := true
    if maze[agentBall] == ' ' {
        stream.Send(ifc.EvNoBallInAgent)
        can = false
    }
    if maze[sectorBall] != ' ' {
        stream.Send(ifc.EvSectorFull)
        can = false
    }
    if can {
        maze[sectorBall] = maze[agentBall]
        maze[agentBall] = ' '
    }
    if win() { 
        stream.Send(ifc.EvGameOver)
        return true
    }
    return false
}
    




func win() bool {
    ballPos := 2
    for ballPos < len(maze) {
        switch ballColor := maze[ballPos]; ballColor {
        case ifc.EvBallRed, ifc.EvBallGreen, ifc.EvBallYellow, ifc.EvBallBlue:
            if ballColor != maze[ballPos-1]+32 {
                return false
            }
        }
        ballPos += 3
        if ballPos%rowLen == 1 {
            ballPos += 2 * rowLen
        }
    }
    return true
}