Skip to content

Commit

Permalink
hashCode() overridden #2
Browse files Browse the repository at this point in the history
  • Loading branch information
mcallisto committed Apr 25, 2024
1 parent 7220bf1 commit dc782d5
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 34 deletions.
52 changes: 35 additions & 17 deletions src/main/scala/io/github/scala_tessella/tessella/Tiling.scala
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,24 @@ class Tiling private(edges: List[Edge]) extends Graph(edges) with Ordered[Tiling
)
case _ => false

/** Initial list of values for equality comparison */
private def startingCode: List[Int] =
List(countPolygons, graphEdges.size, graphNodes.size) ++
orderedRoundedPerimeterAngles.rotationsAndReflections.min.map(_.toInt).toList

/** Full list of values for equality comparison */
private def code: List[Int] =
startingCode ++
inner(tilings =>
val flattened: List[PolygonEdges] =
tilings.flatten
List(tilings.size, flattened.flatten.size, flattened.flatten.nodes.size) ++
flattened.map(_.size).groupBySize.toList.sorted(Ordering[(Int, Int)].reverse).flatMap(List(_, _))
).flatten

override def hashCode(): Int =
code.hashCode()

/** Finds the 2D box */
def toBox: Box =
edges.toBox(coords)
Expand Down Expand Up @@ -682,20 +700,20 @@ object Tiling extends UniTriangle with UniHex with Uni4Hex with Uni5Hex with Lay
def maybe(edges: Edge*): Either[String, Tiling] =
maybe(edges.toList)

/** Filters out duplicate tilings.
*
* @note Reimplementing the wheel, but test shows that factory `distinct` can fail.
*/
def distinctSafe(tilings: List[Tiling]): List[Tiling] =
val found: mutable.ArrayBuffer[Tiling] =
mutable.ArrayBuffer.empty[Tiling]

@tailrec
def loop(remaining: List[Tiling]): List[Tiling] =
remaining match
case Nil => found.toList
case h :: t =>
if !found.contains(h) then found += h
loop(t)

loop(tilings)
// /** Filters out duplicate tilings.
// *
// * @note Reimplementing the wheel, but `distinct` can fail if hashCode is not properly implemented.
// */
// def distinctSafe(tilings: List[Tiling]): List[Tiling] =
// val found: mutable.ArrayBuffer[Tiling] =
// mutable.ArrayBuffer.empty[Tiling]
//
// @tailrec
// def loop(remaining: List[Tiling]): List[Tiling] =
// remaining match
// case Nil => found.toList
// case h :: t =>
// if !found.contains(h) then found += h
// loop(t)
//
// loop(tilings)
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ object Symmetric:
yield
grown
)
Tiling.distinctSafe(tilings.getDefined)
tilings.getDefined.distinct

/** Expands by symmetric axes
*
Expand All @@ -94,5 +94,5 @@ object Symmetric:
*/
def expansion(steps: Int, validity: Tiling => Boolean = _ => true): List[Tiling] =
(0 until steps).foldLeft(List(tiling))((tilings, step) =>
Tiling.distinctSafe(tilings.flatMap(_.expansionStep)).filter(validity)
tilings.flatMap(_.expansionStep).distinct.filter(validity)
)
Original file line number Diff line number Diff line change
Expand Up @@ -146,44 +146,49 @@ class TilingEqualitySpec extends AnyFlatSpec with Helper with ring_seq.Iterating
2--7, 2--3, 3--4, 4--5, 5--6, 6--7, 1--7, 1--6, 1--5, 1--4,
1--3, 1--2, 2--8, 8--9, 9--10, 10--11, 11--12, 7--12
)
val tiling1almostEqual: Tiling =
val tiling1almostSame: Tiling =
Tiling.maybe(List(3--8, 2--12) ++ baseEdges).toOption.get
val tiling2almostEqual: Tiling =
val tiling2almostSame: Tiling =
Tiling.maybe(List(7--8, 6--12) ++ baseEdges).toOption.get

"Two tilings" can "be evaluated with ==" in {
tiling1almostEqual == tiling2almostEqual shouldBe
"Two tilings with different edges" can "be evaluated with ==" in {
tiling1almostSame == tiling2almostSame shouldBe
true
}

they can "be evaluated as equals" in {
tiling1almostEqual.equals(tiling2almostEqual) shouldBe
tiling1almostSame.equals(tiling2almostSame) shouldBe
true
}

they can "be compared" in {
tiling1almostEqual.compare(tiling2almostEqual) shouldBe
tiling1almostSame.compare(tiling2almostSame) shouldBe
0
}

val listed: List[Tiling] =
List(tiling1almostEqual, tiling2almostEqual)
List(tiling1almostSame, tiling2almostSame)

they can "have a different hash code due to a non specialized implementation" in {
they can "have the same hash code" in {
listed.map(_.hashCode()).distinct.size shouldBe
2
1
}

they can "WRONGLY be seen as distinct with standard method" in {
listed.distinct.size shouldBe
2 // WRONG!
they can "have a hash code for the first one" in {
tiling1almostSame.hashCode() shouldBe
-425435535
}

they can "be seen as same with dedicated method" in {
Tiling.distinctSafe(listed).size shouldBe
1
they can "have a hash code for the second one" in {
tiling2almostSame.hashCode() shouldBe
-425435535
}

// they can "be seen as same with dedicated method" in {
// Tiling.distinctSafe(listed).size shouldBe
// 1
// }

val t: Tiling =
sqr4x4Reticulate.maybeRemoveNode(Node(21)).flatMap(_.maybeRemoveNode(Node(5))).unsafe

Expand Down

0 comments on commit dc782d5

Please sign in to comment.