// https://leetcode.com/problems/spiral-matrix
fun spiralOrder(matrix: Array<IntArray>): List<Int> {
    val numIndices = matrix.size * matrix.first().size
    val spiral = mutableListOf<Int>()
    val viewed = Array(matrix.size) { BooleanArray(matrix.first().size) }
    var row = 0
    var col = 0
    var rowOffset = 0
    var colOffset = 1
    while (spiral.size < numIndices) {
        spiral.add(matrix[row][col])
        viewed[row][col] = true
        val isNextIndexValid = validIndex(
            row = row + rowOffset,
            col = col + colOffset,
            lastRow = matrix.lastIndex,
            lastCol = matrix.first().lastIndex
        )
        if (!isNextIndexValid || viewed[row + rowOffset][col + colOffset]) {
            when {
                colOffset == 1 -> {
                    rowOffset = 1
                    colOffset = 0
                }
                rowOffset == 1 -> {
                    rowOffset = 0
                    colOffset = -1
                }
                colOffset == -1 -> {
                    rowOffset = -1
                    colOffset = 0
                }
                else -> {
                    rowOffset = 0
                    colOffset = 1
                }
            }
        }
        row += rowOffset
        col += colOffset
    }
    return spiral
}

private fun validIndex(row: Int, col: Int, lastRow: Int, lastCol: Int): Boolean {
    return row in 0..lastRow && col in 0..lastCol
}

// https://leetcode.com/problems/spiral-matrix
fun spiralOrder(matrix: Array<IntArray>): List<Int> {
    val numIndices = matrix.size * matrix.first().size
    val spiral = mutableListOf<Int>()
    val viewed = Array(matrix.size) { BooleanArray(matrix.first().size) }
    var row = 0
    var col = 0
    var rowOffset = 0
    var colOffset = 1
    while (spiral.size < numIndices) {
        spiral.add(matrix[row][col])
        viewed[row][col] = true
        val isNextIndexValid = validIndex(
            row = row + rowOffset,
            col = col + colOffset,
            lastRow = matrix.lastIndex,
            lastCol = matrix.first().lastIndex
        )
        if (!isNextIndexValid || viewed[row + rowOffset][col + colOffset]) {
            when {
                colOffset == 1 -> {
                    rowOffset = 1
                    colOffset = 0
                }
                rowOffset == 1 -> {
                    rowOffset = 0
                    colOffset = -1
                }
                colOffset == -1 -> {
                    rowOffset = -1
                    colOffset = 0
                }
                else -> {
                    rowOffset = 0
                    colOffset = 1
                }
            }
        }
        row += rowOffset
        col += colOffset
    }
    return spiral
}

private fun validIndex(row: Int, col: Int, lastRow: Int, lastCol: Int): Boolean {
    return row in 0..lastRow && col in 0..lastCol
}
