Last active
November 22, 2019 06:16
-
-
Save cuber5566/f5c10165901927f4cba896073dbee1a0 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package eventpal.com.play | |
import org.junit.Assert | |
import org.junit.Test | |
import kotlin.math.abs | |
class ElevatorTest { | |
interface Elevator { | |
fun getFloor(): Int | |
fun goto(request: Request) | |
fun getPath(): ArrayList<Request> | |
fun getFloorPath(): Array<Int> | |
fun setPath(path: ArrayList<Request>) | |
} | |
enum class Direction { | |
UP, DOWN, UNSPECIFIED | |
} | |
data class Request(val floor: Int, val direction: Direction) | |
val elevator = CuberElevator() | |
val controller = Controller().apply { | |
addElevator(elevator) | |
} | |
fun onGetInnerRequest(elevator: Elevator, floor: Int) { | |
val request = Request(floor, Direction.UNSPECIFIED) | |
controller.addRequest(elevator, request) | |
} | |
fun onGetOuterRequest(floor: Int, direction: Direction) { | |
val request = Request(floor, direction) | |
controller.addRequest(request) | |
} | |
@Test | |
fun `request 1f, i_3`() { | |
elevator.currentFloor = 1 | |
onGetInnerRequest(3) | |
Assert.assertArrayEquals(arrayOf(3), floorPath(elevator)) | |
} | |
@Test | |
fun `request 1f, o_1_up`() { | |
elevator.currentFloor = 1 | |
onGetOuterRequest(1, Direction.UP) | |
Assert.assertArrayEquals(arrayOf(1), floorPath(elevator)) | |
} | |
@Test | |
fun `request 1f, o_3_up `() { | |
elevator.currentFloor = 1 | |
onGetOuterRequest(3, Direction.UP) | |
Assert.assertArrayEquals(arrayOf(3), floorPath(elevator)) | |
} | |
@Test | |
fun `request 1f, 0_3_down `() { | |
elevator.currentFloor = 1 | |
onGetOuterRequest(3, Direction.DOWN) | |
Assert.assertArrayEquals(arrayOf(3), floorPath(elevator)) | |
} | |
@Test | |
fun `request 1f, o_2_up, o_3_up, o_4_up`() { | |
elevator.currentFloor = 1 | |
onGetOuterRequest(2, Direction.UP) | |
onGetOuterRequest(3, Direction.UP) | |
onGetOuterRequest(4, Direction.UP) | |
Assert.assertArrayEquals(arrayOf(2, 3, 4), floorPath(elevator)) | |
} | |
@Test | |
fun `request 1f, o_2_up, o_3_down, o_4_up`() { | |
elevator.currentFloor = 1 | |
onGetOuterRequest(2, Direction.UP) | |
onGetOuterRequest(3, Direction.DOWN) | |
onGetOuterRequest(4, Direction.UP) | |
Assert.assertArrayEquals(arrayOf(2, 4, 3), floorPath(elevator)) | |
} | |
@Test | |
fun `request 3f, o_2_up, o_4_down, o_5_up`() { | |
elevator.currentFloor = 1 | |
onGetOuterRequest(2, Direction.UP) | |
onGetOuterRequest(4, Direction.DOWN) | |
onGetOuterRequest(5, Direction.UP) | |
Assert.assertArrayEquals(arrayOf(2, 5, 4), floorPath(elevator)) | |
} | |
@Test | |
fun `request 3f, o_2_up, o_4_down, o_5_up, i_3`() { | |
elevator.currentFloor = 1 | |
onGetOuterRequest(2, Direction.UP) | |
onGetOuterRequest(4, Direction.DOWN) | |
onGetOuterRequest(5, Direction.UP) | |
onGetInnerRequest(3) | |
Assert.assertArrayEquals(arrayOf(2, 3, 5, 4), floorPath(elevator)) | |
} | |
private fun floorPath(elevator: Elevator): Array<Int> { | |
return elevator.getPath().map { it.floor }.toTypedArray() | |
} | |
} | |
class CuberElevator : ElevatorTest.Elevator { | |
var currentFloor: Int = 1 | |
var direction = ElevatorTest.Direction.UNSPECIFIED | |
var mPath = ArrayList<ElevatorTest.Request>() | |
override fun getFloor() = currentFloor | |
override fun goto(request: ElevatorTest.Request) { | |
currentFloor = request.floor | |
direction = request.direction | |
} | |
override fun getPath() = mPath | |
override fun getFloorPath() = mPath.map { it.floor }.toTypedArray() | |
override fun setPath(path: ArrayList<ElevatorTest.Request>) { | |
this.mPath = path | |
} | |
} | |
class Controller { | |
val elevatorList = ArrayList<ElevatorTest.Elevator>() | |
fun addElevator(elevator: ElevatorTest.Elevator) { | |
elevatorList.add(elevator) | |
} | |
fun addRequest(request: ElevatorTest.Request) { | |
// 可能可以加入分配request給多個電梯的邏輯 | |
val elevator = if (request.direction != ElevatorTest.Direction.UNSPECIFIED) { | |
assignElevator() | |
} else { | |
} | |
addRequest(elevatorList.first(), request) | |
} | |
fun assignElevator(): ElevatorTest.Elevator { | |
var min = 0 | |
var index = 0 | |
elevatorList.forEachIndexed { i, elevator -> | |
val path = calPathLength(elevator.getPath()) | |
if (path < min) { | |
min = path | |
index = i | |
} | |
} | |
return elevatorList[index] | |
} | |
private fun addRequest(elevator: ElevatorTest.Elevator, request: ElevatorTest.Request) { | |
val path = setupPath(elevator, request) | |
elevator.setPath(path) | |
} | |
private fun setupPath( | |
elevator: ElevatorTest.Elevator, | |
newRequest: ElevatorTest.Request | |
): ArrayList<ElevatorTest.Request> { | |
val resultPath = ArrayList<ElevatorTest.Request>() | |
val newPath = elevator.getPath().plus(newRequest) | |
val firstFloor = elevator.getFloor() | |
val firstRequest = newPath[0] | |
val firstDirection = when { | |
firstFloor < firstRequest.floor -> ElevatorTest.Direction.UP | |
firstFloor > firstRequest.floor -> ElevatorTest.Direction.DOWN | |
else -> ElevatorTest.Direction.UNSPECIFIED | |
} | |
val upPath = ArrayList<ElevatorTest.Request>() | |
val downPath = ArrayList<ElevatorTest.Request>() | |
val unspecifiedPath = ArrayList<ElevatorTest.Request>() | |
for (request in newPath) { | |
when (request.direction) { | |
ElevatorTest.Direction.UP -> upPath.add(request) | |
ElevatorTest.Direction.DOWN -> downPath.add(request) | |
ElevatorTest.Direction.UNSPECIFIED -> unspecifiedPath.add(request) | |
} | |
} | |
upPath.sortBy { it.floor } | |
downPath.sortByDescending { it.floor } | |
when (firstDirection) { | |
ElevatorTest.Direction.UP -> { | |
resultPath.addAll(upPath.filter { it.floor > firstFloor }) | |
resultPath.addAll(downPath) | |
} | |
ElevatorTest.Direction.DOWN -> { | |
resultPath.addAll(downPath.filter { it.floor < firstFloor }) | |
} | |
ElevatorTest.Direction.UNSPECIFIED -> { | |
resultPath.add(newRequest) | |
} | |
} | |
unspecifiedPath.forEach { insertUnspecifiedRequest(resultPath, it) } | |
return resultPath | |
} | |
private fun insertUnspecifiedRequest( | |
path: ArrayList<ElevatorTest.Request>, | |
request: ElevatorTest.Request | |
) { | |
var index = 0 | |
while (true) { | |
if (index + 1 >= path.size) { | |
path.add(request) | |
return | |
} | |
val start = path[index].floor | |
val end = path[index + 1].floor | |
if (inRange(start, end, request.floor)) { | |
path.add(index + 1, request) | |
return | |
} | |
index++ | |
} | |
} | |
private fun inRange(start: Int, end: Int, target: Int): Boolean { | |
return (start + end) / 2 >= target | |
} | |
private fun calPathLength(path: ArrayList<ElevatorTest.Request>): Int { | |
if (path.size <= 1) return 0 | |
var sum = 0 | |
var index = 0 | |
while (true) { | |
val from = path[index] | |
val to = path[index + 1] | |
sum += abs(from.floor - to.floor) | |
if (index + 1 >= path.size) { | |
break | |
} | |
index++ | |
} | |
return sum | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment