A side note:
type POSITION = (Byte, Byte)
That gets erased to (rather heavy):
type POSITION = Tuple2[Object, Object]
because Tuple2 isn’t specialized for Bytes https://github.com/scala/scala/blob/2.13.x/src/library/scala/Tuple2.scala
final case class Tuple2[@specialized(Int, Long, Double, Char, Boolean/*, AnyRef*/) +T1, @specialized(Int, Long, Double, Char, Boolean/*, AnyRef*/) +T2](_1: T1, _2: T2)
extends Product2[T1, T2]
Solution with a set of named functions https://scastie.scala-lang.org/LZmsBK7YScWWg2K2xNIENw
type Position = (Byte, Byte) // erases to heavy Tuple2[Object, Object]
def genSymmetries(n: Byte, placement: Set[Position]): List[Set[Position]] = {
type Transform = (Byte, Byte) => Position
def /(x: Byte): Byte = (n - x + 1).toByte
val id: Transform = (x, y) => (x, y)
val r90: Transform = (x, y) => (/(y), x) // -y, x
val r180: Transform = (x, y) => (/(x), /(y)) // -x, -y
val r270: Transform = (x, y) => (y, /(x)) // y, -x
val mx: Transform = (x, y) => (x, /(y)) // x, -y mirror about x axis
val my: Transform = (x, y) => (/(x), y) // -x, y mirror about y axis
val mxy: Transform = (x, y) => (y, x) // y, x
val mxr90: Transform = (x, y) => (/(y), /(x)) // -y, -x
val transforms: List[(Byte, Byte) => Position] =
List(id, r90, r180, r270, my, mx, mxy, mxr90)
transforms.map { transform =>
val tupledTransform: Position => Position = transform.tupled
placement.map { case p @ (x, y) =>
transform(x, y)
// or if tupling is needed for some reason then
tupledTransform(p)
}
}
}
genSymmetries(5, Set(3.toByte -> 2.toByte)).foreach(println)