Skip to content

Instantly share code, notes, and snippets.

@cuber5566
Last active November 22, 2019 06:16
Show Gist options
  • Save cuber5566/f5c10165901927f4cba896073dbee1a0 to your computer and use it in GitHub Desktop.
Save cuber5566/f5c10165901927f4cba896073dbee1a0 to your computer and use it in GitHub Desktop.
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