---
# System prepended metadata

title: "[LeetCode] 1041.\_Robot Bounded In Circle"
tags: [LeetCode]

---

[LeetCode] 1041. Robot Bounded In Circle
===
###### tags: `LeetCode`

## 題目
On an infinite plane, a robot initially stands at `(0, 0)` and faces north. The robot can receive one of three instructions:

- `"G"`: go straight 1 unit;
- `"L"`: turn 90 degrees to the left;
- `"R"`: turn 90 degrees to the right.

The robot performs the `instructions` given in order, and repeats them forever.

Return `true` if and only if there exists a circle in the plane such that the robot never leaves the circle.

**Example 1:**

```
Input: instructions = "GGLLGG"
Output: true
Explanation: The robot moves from (0,0) to (0,2), turns 180 degrees, and then returns to (0,0).
When repeating these instructions, the robot remains in the circle of radius 2 centered at the origin.
```

**Example 2:**

```
Input: instructions = "GG"
Output: false
Explanation: The robot moves north indefinitely.
```

**Example 3:**

```
Input: instructions = "GL"
Output: true
Explanation: The robot moves from (0, 0) -> (0, 1) -> (-1, 1) -> (-1, 0) -> (0, 0) -> ...
```

**Constraints:**

- `1 <= instructions.length <= 100`
- `instructions[i]` is `'G'`, `'L'` or, `'R'`.


### 第一版
做法：
先想辦法走到底，再判斷是否能走回原點

```=Java
class Solution {
    enum class Direction(val face: Int, val x: Int, val y: Int){
				// face 為面向的方位
				// 方位順序：N(0) -> E(1) -> S(2) -> W(3) -> N(0) -> ...
				// 右轉('R') = 方位 + 1，左轉('L') = 方位 - 1
        NORTH(0, 0, 1),
        EAST(1, 1, 0),
        SOUTH(2, 0, -1),
        WEST(3, -1, 0)
    }
    companion object {
        private const val STRAIGHT = 'G'
        private const val LEFT = 'L'
        private const val RIGHT = 'R'
				private const val DIRECTION_COUNT = 4
    }
    
    fun isRobotBounded(instructions: String): Boolean {
        // 初始位置
        var tmpFace = Direction.NORTH
        var tmpX = 0
        var tmpY = 0
        // TODO 可以先移除 "RRRR" & "LLLL"
        // 先想辦法走到底
        // 再判斷是否能走回原點
        
        // 先走完整個 instructions
        instructions.forEach {
            when (it) {
                STRAIGHT -> {
                    tmpX += tmpFace.x
                    tmpY += tmpFace.y
                }
                LEFT -> {
                    // 新的方向
                    var newFace = tmpFace.face - 1
                    if (newFace < 0) {
                        newFace += DIRECTION_COUNT
                    }
                    tmpFace = transToDirection(newFace)
                }
                RIGHT -> {
                    var newFace = tmpFace.face + 1
                    if (newFace >= DIRECTION_COUNT) {
                        newFace -= DIRECTION_COUNT
                    }
                    tmpFace = transToDirection(newFace)
                }
            }
        }
        // println(tmpFace.face)
        // println("x: $tmpX, y: $tmpY")
        
        // 判斷是否能回到原點
        // 回到原點
        if (tmpX == 0 && tmpY == 0) {
            return true
        }
        
        if (tmpFace == Direction.NORTH) {
            return false
        }
        
        return true
    }

    fun transToDirection(currentFace: Int): Direction {
        return when (currentFace) {
            Direction.NORTH.face -> Direction.NORTH
            Direction.EAST.face -> Direction.EAST
            Direction.SOUTH.face -> Direction.SOUTH
            else -> Direction.WEST
        }
    }
}
```
**Success**

[Details](https://leetcode.com/submissions/detail/621408508/)

Runtime: 224 ms, faster than 43.24% of Kotlin online submissions for Robot Bounded In Circle.

Memory Usage: 33.8 MB, less than 70.95% of Kotlin online submissions for Robot Bounded In Circle.

---

### 第二版
試圖縮短時間
若遇到連續轉方向，一併判斷

```=Java
class Solution {
    enum class Direction(val face: Int, val x: Int, val y: Int){
        NORTH(0, 0, 1),
        EAST(1, 1, 0),
        SOUTH(2, 0, -1),
        WEST(3, -1, 0)
    }
    companion object {
        private const val STRAIGHT = 'G'
        private const val LEFT = 'L'
        private const val RIGHT = 'R'
        private const val DIRECTION_COUNT = 4
    }
    
    fun isRobotBounded(instructions: String): Boolean {
        // 初始位置
        var tmpFace = Direction.NORTH
        var tmpX = 0
        var tmpY = 0
        // 先想辦法走到底
        // 再判斷是否能走回原點
        
        // 先走完整個 instructions
        
        // note:
        // for (i in 0 until instructions.length) {}
        // 因為 i cannot be reassigned
        // 所以改成 var i 的方式
        // end note
        
        var i = 0
        while (i < instructions.length) {
            // 計算有連續幾個直走
            var count = 0
            for (j in i until instructions.length) {
                if (instructions[j] == STRAIGHT) {
                    count++
                } else {
                    break
                }
            }
            if (count != 0) {
                tmpX += tmpFace.x * count
                tmpY += tmpFace.y * count
                i += count
                continue
            }
            
            // 計算有連續幾個轉向
            count = 0
            for (j in i until instructions.length) {
                if (instructions[j] != STRAIGHT) {
                    count++
                } else {
                    break
                }
            }
            var faceSum = 0
            for (j in i until i + count) {
                if (instructions[j] == LEFT) {
                    faceSum--
                } else {
                    faceSum++
                }
            }
            
            i += count
            if (faceSum % DIRECTION_COUNT == 0) {// 沒旋轉
                continue
            }
            // 旋轉目前的方位
            var newFace = (tmpFace.face + faceSum) % DIRECTION_COUNT
            if (newFace < 0) {
                newFace += DIRECTION_COUNT
            }
            tmpFace = transToDirection(newFace)
        }
        // println("f: ${tmpFace.face} ($tmpX, $tmpY)")
        
        // 判斷是否能回到原點
        // 回到原點
        if (tmpX == 0 && tmpY == 0) {
            return true
        }
        
        if (tmpFace == Direction.NORTH) {
            return false
        }
        
        return true
    }

    fun transToDirection(currentFace: Int): Direction {
        return when (currentFace) {
            Direction.NORTH.face -> Direction.NORTH
            Direction.EAST.face -> Direction.EAST
            Direction.SOUTH.face -> Direction.SOUTH
            else -> Direction.WEST
        }
    }
}
```
**Success**

[Details](https://leetcode.com/submissions/detail/621445613/)

Runtime: 200 ms, faster than 60.13% of Kotlin online submissions for Robot Bounded In Circle.

Memory Usage: 34.5 MB, less than 29.73% of Kotlin online submissions for Robot Bounded In Circle.
