solved

[์•Œ๊ณ ๋ฆฌ์ฆ˜ ๋ฌธ์ œ/2020 KAKAO BLIND RECRUITMENT] ์ž๋ฌผ์‡ ์™€ ์—ด์‡ 

์ •๋‹ต์ฝ”๋“œ

import kotlin.test.*
import kotlin.time.*

enum class Direction {
    `0`{
        override fun x(x: Int, y: Int, size : Int) = x
        override fun y(x: Int, y: Int, size : Int) = y
    }, `90`{
        override fun x(x: Int, y: Int, size : Int) = (size - 1) - y
        override fun y(x: Int, y: Int, size : Int) = x
    }, `180`{
        override fun x(x: Int, y: Int, size : Int) = (size - 1) - x
        override fun y(x: Int, y: Int, size : Int) = (size - 1) - y
    }, `270`{
        override fun x(x: Int, y: Int, size : Int) = y
        override fun y(x: Int, y: Int, size : Int) = (size - 1) - x
    };

    abstract fun x(x: Int, y: Int, size : Int) : Int
    abstract fun y(x: Int, y: Int, size : Int) : Int
}

class Solution {

    fun solution(key: Array<IntArray>, lock: Array<IntArray>): Boolean {
        enumValues<Direction>().forEach { 
            var rotated = rotate(key, it)
            for(moveX in -(key.size - 1) .. (lock.size-1) + (key.size-1)) {
                for(moveY in -(key.size - 1) .. (lock.size-1) + (key.size-1)) {
                    var movedKey = moveKey(rotated, lock.size, moveX, moveY)
                    var match = plus(movedKey, lock)
                    if(checkOpen(match)) return true
                }
            }
        }
        return false
    }


    fun checkOpen(matrix: Array<IntArray>) : Boolean {
        return matrix.any{ a -> a.any{ it != 1 } }.not()
    }

    fun createMatrix(size : Int) : Array<IntArray> {
        return Array(size, { IntArray(size, {0}) })
    }

    fun moveKey(key: Array<IntArray>, lockSize : Int, moveX : Int, moveY : Int) : Array<IntArray> {
        var moveKey = createMatrix(lockSize)
        for(x in 0 .. lockSize - 1){
            for(y in 0 .. lockSize - 1){

                var movedX = x + moveX
                var movedY = y + moveY

                var validation = x >= 0 && x < key.size && y >= 0 && y < key.size
                var ableToMove = movedX >= 0 && movedX < lockSize && movedY >= 0 && movedY < lockSize
                if(validation && ableToMove) {
                    moveKey[movedX][movedY] = key[x][y]
                }
            } 
        }
        return moveKey
    }

    fun rotate(matrix: Array<IntArray>, direction: Direction) : Array<IntArray> {    
        return createMatrix(matrix.size).mapIndexed {i, e1 -> 
            e1.mapIndexed { j, _ -> 
                var newX = direction.x(i, j, matrix.size)
                var newY = direction.y(i, j, matrix.size)
                matrix[newX][newY]
            }.toIntArray()
        }.toTypedArray()
    }

    fun plus(matrixA: Array<IntArray>, matrixB: Array<IntArray>) : Array<IntArray> {
        return matrixA.mapIndexed { i, e1 -> e1.mapIndexed { j, e2 -> e2 + matrixB[i][j] }.toIntArray() }.toTypedArray()
    }
}


class SolutionTest(val solution : Solution, val testTool : TestStrategy = NormalTest()) {

    
    /*
     * 000       matrix[0][0]  matrix[0][1]  matrix[0][2]
     * 100       matrix[1][0]  matrix[1][1]  matrix[1][2]
     * 011       matrix[2][0]  matrix[2][1]  matrix[2][2]
    */
    fun draw(matrix: Array<IntArray>) {
        matrix.forEach{       
            it.forEach{           
                a ->print(a)
            }
            println("")
        }
        println("---")
    }
    
    fun testSolution() {
        val key = arrayOf(intArrayOf(0,0,0),intArrayOf(1,0,0),intArrayOf(0,1,1))
        val lock = arrayOf(intArrayOf(1,1,1),intArrayOf(1,1,0),intArrayOf(1,0,1))
        val answer = true

        testTool.test(answer) {
            solution.solution(key, lock)
        }
    }

}

interface TestStrategy {
    fun<T> test(answer : T, testBlock: () -> T)
}

class NormalTest : TestStrategy {
    override fun<T> test(answer : T, testBlock: ()->T) {
        val result = testBlock()
        println("------------")
        assertEquals(answer, result, "epected : $answer, actural : $result")
    }
}

class EfficiencyTest : TestStrategy {
    override fun<T> test(answer : T, testBlock: ()->T) {
        val (result, duration) = measureTimedValue { testBlock() }
        println("------------")
        println("duration : $duration")
        assertEquals(answer, result, "epected : $answer, actural : $result")
    }
}

fun main() {
    val solution = Solution()
    val solutionTest = SolutionTest(solution)

    solutionTest.testSolution()
}

 

ํ’€์ด๋ฐฉ์‹

์กฐ๊ธˆ ๋ฌด์‹ํ•œ ๋ฐฉ๋ฒ•์ผ์ง€ ๋ชจ๋ฅด์ง€๋งŒ ์—ด์‡ ์™€ ์ž๋ฌผ์‡ ์˜ ์ตœ๋Œ€ ํฌ๊ธฐ๊ฐ€ 20์ด๋ผ์„œ ๊ฐ€๋Šฅํ•œ ๋ชจ๋“  ๊ฒฝ์šฐ์˜ ์ˆ˜๋ฅผ ํ™•์ธํ•˜๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ ์ ‘๊ทผํ–ˆ๋‹ค.

ํ‚ค์˜ ํšŒ์ „๊ณผ ์›€์ง์ž„์— ๋”ฐ๋ฅธ ๋ณ€ํ˜•๋œ ํ‚ค๊ฐ’์„ ๊ฐ€์ง€๊ณ  ์˜ฌ ์ˆ˜ ์žˆ๋„๋ก (roatate, moveKey) ํ•จ์ˆ˜๋ฅผ ๊ฐ๊ฐ ๊ตฌํ˜„ํ–ˆ๋‹ค.

moveKey๋Š” ์›€์ง์ธ ๊ฒฐ๊ณผ๋กœ ์ž๋ฌผ์‡ ํฌ๊ธฐ์˜ 0๋ฐฐ์—ด์—์„œ ๋ณ€ํ˜•๋œ ํ‚ค์˜ ๋Œ๊ธฐ ๋ถ€๋ถ„๋งŒ 1์ด ๋˜๋„๋ก ๋ฐฐ์—ด์„ ๋ฐ˜ํ™˜ํ–ˆ๊ณ ,

๋‹ต ๋„์ถœ์€ ์ž๋ฌผ์‡ ์™€ ๋ณ€ํ˜•๋œ ํ‚ค์˜ ๊ฐ ์›์†Œ๊ฐ’์„ ๋”ํ•ด ๋ชจ๋“  ์›์†Œ๊ฐ€ 1์ด ๋‚˜์˜ค๋Š” ๊ฒฝ์šฐ๋ฅผ open์œผ๋กœ ๊ทœ์ •ํ–ˆ๋‹ค.