This is a program to solve: Images with all Colors from Code Golf:Make images where each pixel is a unique color (no color is used twice  and no color is missing).Create the image purely algorithmically.Image must be 256128 (or grid that can be screenshot and saved at 256128)Use all 15-bit colors (15-bit colors are the 32768 colors that can be made by mixing 32 reds, 32 greens, and 32 blues, all in equidistant steps and equal ranges. Example: in 24 bits images (8 bit per channel), the range per channel is 0..255 (or 0..224), so divide it up into 32 equally spaced shades.)This is my first Scala application, and my first Object Oriented application for a long time. So, I have a Picture class where you can manipulate(get/set) pixels; and an abstract Painter class which produces a (maybe partial) Picture. And there are different painters inheriting from it for different styles.Please focus on the application design instead of the algorithm for drawing picture when criticising. I specifically need criticisms for:OOP design: Did I use any anti-patterns? How would you model the solution?Scala: Is this idiomatic Scala? What is missing?Syntax suggestions: It looks like Scala has many syntactic structures and sugars. Is there something which can shorten the code, or make it clearer?Full code on GitHub, for additional contextimport com.sksamuel.scrimage._import java.awt.image.BufferedImageimport java.awt.image.BufferedImage._import scala.collection.immutable.Seqimport scala.collection.mutable.Setimport scala.util._object Main extends App {  val im1 = new DirectionalPainter( new Picture(256, 128)                                  , Set(LeftOblique, RightOblique)                                  ).paint(0.1)  val im2 = new AvgPainter(im1).paint  im2.save(/tmp/testOut.png)}object Painter {  def colorSSD(c1: RGBColor, c2: RGBColor): Double = {    val RGBColor(r1, g1, b1, _) = c1    val RGBColor(r2, g2, b2, _) = c2    Math.sqrt(Math.pow(r1-r2, 2) + Math.pow(g1-g2, 2) + Math.pow(b1-b2, 2))  }  def coordSSD(c1: (Int, Int), c2: (Int, Int)): Double = {    val (x1, y1) = c1    val (x2, y2) = c2    Math.sqrt(Math.pow(x1-x2, 2) + Math.pow(y1-y2, 2))  }  def colorAvg(colors: Seq[RGBColor]): Option[RGBColor] = {    if(colors.length == 0) None    else {      val res = ((0.0, 0.0, 0.0) /: colors){        case ((r, g, b), RGBColor(r_, g_, b_, _)) => (r+r_, g+g_, b+b_)      } match {        case (r, g, b) => {          val num = colors.length          RGBColor((r/num).round.toInt, (g/num).round.toInt, (b/num).round.toInt)        }      }      Some(res)    }  }}case class Coord(val x: Int, val y: Int) {  def +(other: Coord) = Coord(x+other.x, y+other.y)  def -(other: Coord) = Coord(x-other.x, y-other.y)}abstract class Painter(private val picture: Picture) {  private val width = picture.width  private val height = picture.height  private val possibleColors: Set[RGBColor] = {    val numColors = (width * height).toDouble    val depth = Math.pow(numColors, 1.0/3.0).round.toInt    assert(depth < 256)    val mul = 256/depth    val c = for ( r <- Stream.range(0, depth)                ; g <- Stream.range(0, depth)                ; b <- Stream.range(0, depth)              )            yield RGBColor(r * mul, g * mul, b * mul)    Set(c:_*)  }  private val possibleCoords: Set[Coord] = {    val c = for ( x <- Stream.range(0, width)                ; y <- Stream.range(0, height)                )            yield Coord(x, y)    Set(c:_*)  }  for(coord <- possibleCoords) {    picture.get(coord) match {      case Some(color) => set(coord, color)      case None => Unit    }  }  assert(possibleCoords.size == possibleColors.size)  final def set(coord: Coord, color: RGBColor): Boolean = {    val r = coordEmpty(coord) && colorAvailable(color)    if(r) {      this.possibleColors.remove(color)      this.possibleCoords.remove(coord)      picture.set(coord, Some(color))    }    if(Random.nextDouble() < 0.05) {      val percent = (1 - (unusedColors.length.toDouble / (width * height) )) * 100      println(f$percent%1.2f)    }    r  }  final def get(coord: Coord): Option[RGBColor] = this.picture.get(coord)  final def coordValid(coord: Coord): Boolean    = 0 <= coord.x && coord.x < width && 0 <= coord.y && coord.y < height  final def coordEmpty(coord: Coord): Boolean    = possibleCoords.contains(coord)  final def colorAvailable = possibleColors.contains _  final def unusedColors: Stream[Color] = possibleColors.toStream  final def unusedCoords: Stream[Coord] = possibleCoords.toStream  private final def randomFromSet[a](set: Set[a]): Option[a]    = if(set.isEmpty) None else Some(set.toVector(Random.nextInt(set.size)))  final def randomColor: Option[Color] = randomFromSet(possibleColors)  final def randomCoord: Option[Coord] = randomFromSet(possibleCoords)  final def neighborsOf(windowSize: Int, coord: Coord): Seq[Coord] = {    val xs = for { i <- -windowSize to windowSize; j <- -windowSize to windowSize                 ; if (i != 0 || j != 0) }             yield Coord(coord.x+i, coord.y+j)    xs.filter(coordValid)  }  final def paint(percentage: Double): Picture = {    assert(0 <= percentage && percentage <= 1)    while(unusedColors.size > width * height * (1-percentage)) step    this.picture  }  final def paint: Picture = paint(1)  def step: Unit}class Picture(val width: Int, val height: Int) {  private val array: Array[Option[RGBColor]] = Array.fill(width * height)(None)  def get(coord: Coord): Option[RGBColor]    = this.array(coord.x * height + coord.y)  def set(coord: Coord, v: Option[RGBColor]): Unit    = this.array(coord.x * height + coord.y) = v  def save(path: String): Unit = {    val im = new Image( new BufferedImage(width, height, TYPE_INT_RGB)                      , new ImageMetadata(Nil)                      )    for(x <- 0 until width)      for(y <- 0 until height) {        val color = this.get(Coord(x, y)).getOrElse(Color.White).toPixel        im.setPixel(x, y, color)      }    im.output(path)  }}class LinearPainter(val picture: Picture)  extends Painter(picture) {  override def step = {    val color = unusedColors.minBy(_.toInt);    val coord = unusedCoords.minBy(coord => (coord.x, coord.y));    assert(this.set(coord, color))  }}class RandomPainter(val picture: Picture)  extends Painter(picture) {  override def step = {    assert(this.set(randomCoord.get, randomColor.get))  }}class AvgPainter(val picture: Picture)  extends Painter(picture) {  override def step = {    val coords = unusedCoords.map(      coord => (coord, (neighborsOf(1, coord).map(get)).flatten)    )    val coordsSorted = coords.sortBy(- _._2.length)    val chosenOnes = coordsSorted.takeWhile(_._2.length == coordsSorted.head._2.length)    for((coord, neighbors) <- chosenOnes) {      val target = Painter.colorAvg(neighbors).get      val color = unusedColors.par.minBy(Painter.colorSSD(target, _))      assert(set(coord, color))    }  }}abstract class Direction { val unit: Coord }case object Horizontal   extends Direction { val unit = Coord(1, 0) }case object Vertical     extends Direction { val unit = Coord(0, 1) }case object LeftOblique  extends Direction { val unit = Coord(1, 1) }case object RightOblique extends Direction { val unit = Coord(1, -1) }class DirectionalPainter(val picture: Picture, val directions: Set[Direction])  extends Painter(picture) {  assert(directions.size > 0)  override def step = {    val directions_ = directions.toIndexedSeq    val direction = directions_(Random.nextInt(directions_.length))    val mid = randomCoord.get    val bs = Stream.iterate(mid)(_ - direction.unit).takeWhile(coordEmpty _)    val fs = Stream.iterate(mid)(_ + direction.unit).takeWhile(coordEmpty _).drop(1)    val coords = bs.reverse #::: fs    val c = randomColor.get    val colors = unusedColors.sortBy(Painter.colorSSD(c, _))    for((coord, color) <- coords.zip(colors)) assert(set(coord, color))  }}By the way, here is the current output if you are interested:
All RGB colors in one image
beginner;scala