Skip to content

Instantly share code, notes, and snippets.

@li2
Last active August 18, 2019 02:32
Show Gist options
  • Save li2/dc7ffb9c6a2375b0a42343d3b1956c46 to your computer and use it in GitHub Desktop.
Save li2/dc7ffb9c6a2375b0a42343d3b1956c46 to your computer and use it in GitHub Desktop.
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