Last active
August 18, 2019 02:32
-
-
Save li2/dc7ffb9c6a2375b0a42343d3b1956c46 to your computer and use it in GitHub Desktop.
run online https://pl.kotl.in/sVukJHZQU
This file contains hidden or 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
import kotlin.math.roundToInt | |
/** | |
* Colour in RGB, with each value between 0 – 255 (e.g. R=255, G=0, B=0 would imply a red chart) | |
* | |
* @throws IllegalArgumentException if one of the parameters [r], [g] and [b] is out of bound [0, 255] | |
*/ | |
data class Colour(val r: Int, val g: Int, val b: Int) { | |
init { | |
if (r !in QUALIFIED_RANGE || g !in QUALIFIED_RANGE || b !in QUALIFIED_RANGE) | |
throw IllegalArgumentException("($r, $g, $b) must be in range $QUALIFIED_RANGE ") | |
} | |
fun average(other: Colour) = | |
Colour(((r + other.r) / 2f).roundToInt(), ((g + other.g) / 2f).roundToInt(), ((b + other.b) / 2f).roundToInt()) | |
companion object { | |
private val QUALIFIED_RANGE = 0..255 | |
} | |
} | |
/** | |
* A point on a chart, with each value between 0 - 100. | |
* | |
* @throws IllegalArgumentException if one of the parameters [x] and [y] is out of bound [0, 100] | |
*/ | |
data class Coordinate(val x: Int, val y: Int) { | |
init { | |
if (x !in QUALIFIED_RANGE || y !in QUALIFIED_RANGE) | |
throw IllegalArgumentException("($x, $y) must be in range $QUALIFIED_RANGE ") | |
} | |
companion object { | |
private val QUALIFIED_RANGE = 0..100 | |
} | |
} | |
sealed class Shape { | |
abstract fun intersects(other: Shape): Boolean | |
abstract fun contains(x: Int, y: Int): Boolean | |
} | |
/** | |
* A rectangle area is specified by its [topLeft] coordinate and its [bottomRight] coordinate. | |
*/ | |
data class Rectangle(val topLeft: Coordinate, val bottomRight: Coordinate) : Shape() { | |
override fun intersects(other: Shape) = when (other) { | |
is Rectangle -> !(other.bottomRight.x < this.topLeft.x | |
|| other.topLeft.x > this.bottomRight.x | |
|| other.bottomRight.y < this.topLeft.y | |
|| other.topLeft.y > this.bottomRight.y) | |
} | |
override fun contains(x: Int, y: Int) = | |
x >= topLeft.x && y >= topLeft.y && x <= bottomRight.x && y <= bottomRight.y | |
} | |
data class Chart(val shape: Shape, val colour: Colour) | |
/** | |
* View with [charts]. | |
* | |
* @throws IllegalArgumentException if [charts] contain more that 2 charts. | |
*/ | |
data class View(val charts: List<Chart>) { | |
init { | |
if (charts.size > 2) | |
throw IllegalArgumentException("view can contain a maximum of 2 charts at a time") | |
} | |
fun doChartsOverlap() = when { | |
charts.size == 2 -> charts[0].shape.intersects(charts[1].shape) | |
else -> false | |
} | |
/** | |
* Get the RGB colour of a given coordinate. | |
* | |
* If two charts overlap the colour of the point should be the average of the two colours. | |
* If the point is not in the charts, return null. | |
*/ | |
fun getColour(x: Int, y: Int): Colour? { | |
val colours = mutableListOf<Colour>() | |
charts.forEach { chart -> | |
if (chart.shape.contains(x, y)) colours.add(chart.colour) | |
} | |
return when (colours.size) { | |
2 -> colours[0].average(colours[1]) | |
1 -> colours[0] | |
else -> null | |
} | |
} | |
} | |
fun main() { | |
val view = View( | |
listOf( | |
Chart(Rectangle(Coordinate(0, 0), Coordinate(50, 50)), Colour(255, 0, 0)), | |
Chart(Rectangle(Coordinate(25, 25), Coordinate(100, 100)), Colour(0, 255, 0)) | |
) | |
) | |
println(view.doChartsOverlap()) | |
println(view.getColour(10, 10)) | |
println(view.getColour(30, 30)) | |
println(view.getColour(60, 60)) | |
println(view.getColour(130, 130)) | |
} | |
//true | |
//Colour(r=255, g=0, b=0) | |
//Colour(r=128, g=128, b=0) | |
//Colour(r=0, g=255, b=0) | |
//null |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment