Skip to content

Commit 337b9a6

Browse files
committed
refactoring: upgrade to metarules 0.7.1 (new TileOrientationCache implementation)
1 parent a93c7a5 commit 337b9a6

5 files changed

Lines changed: 29 additions & 27 deletions

File tree

build.sbt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import io.github.memo33.metarules.meta._, com.sc4nam.module, module.syntax._
2020
import Implicits._, Network._, Flags._, RotFlip._, Rule.{CopyTile => %}, group.SymGroup._
2121
lazy val resolve = module.Main.resolveSafely
2222
lazy val preimage = module.ReverseResolver.create()
23-
implicit lazy val context: RuleTransducer.Context = RuleTransducer.Context(resolve, module.RegenerateTileOrientationCache.loadCache(), module.MirrorVariants.preprocessor)
23+
implicit lazy val context: RuleTransducer.Context = RuleTransducer.Context(module.Main.resolve, module.RegenerateTileOrientationCache.loadCache(), module.MirrorVariants.preprocessor)
2424
def transduce(rule: Rule[SymTile]): Unit = RuleTransducer(rule)(context).map(_.toRul2String).foreach(println)
2525
"""
2626

@@ -71,4 +71,4 @@ libraryDependencies += "tv.cntt" %% "scaposer" % "1.11.1" cross CrossVersion.for
7171

7272
libraryDependencies += "io.github.memo33" %% "scdbpf" % "0.2.0" cross CrossVersion.for3Use2_13
7373

74-
libraryDependencies += "io.github.memo33" %% "metarules" % "0.7.0"
74+
libraryDependencies += "io.github.memo33" %% "metarules" % "0.7.1"

src/main/scala/module/CompileAllMetarules.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ object CompileAllMetarules {
3131

3232
/** Add additional rule generators here.
3333
*/
34-
def compileMetarulesOnce(tileOrientationCache: collection.mutable.Map[Int, Set[RotFlip]]): Unit = {
34+
def compileMetarulesOnce(tileOrientationCache: RuleTransducer.TileOrientationCache): Unit = {
3535
LOGGER.info("compiling FlexFly metarule code")
3636
flexfly.CompileFlexFlyCode.start(tileOrientationCache = tileOrientationCache)
3737
LOGGER.info("compiling RRW metarule code")

src/main/scala/module/Main.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,15 @@ abstract class AbstractMain {
2525
lazy val resolveSafely: IdResolver = new PartialFunction[Tile, IdTile] {
2626
def isDefinedAt(tile: Tile) = resolve.isDefinedAt(tile)
2727
def apply(tile: Tile) = try resolve.apply(tile) catch {
28-
case scala.util.control.NonFatal(e) =>
29-
throw new IllegalArgumentException(s"ID resolution failed for tile $tile", e)
28+
case e: RuleTransducer.ResolutionFailed => throw e
29+
case scala.util.control.NonFatal(e) => throw new RuleTransducer.ResolutionFailed(tile, rule = None, reason = e, frame = None)
3030
}
3131
}
3232

3333
def main(args: Array[String]): Unit = start()
3434

3535
/** Creates a generator with a new context, runs its start method and outputs the resulting RUL2 code to file. */
36-
def start(file: File = file, tileOrientationCache: collection.mutable.Map[Int, Set[RotFlip]] = null): Unit = {
36+
def start(file: File = file, tileOrientationCache: RuleTransducer.TileOrientationCache = null): Unit = {
3737
if (tileOrientationCache == null) {
3838
RegenerateTileOrientationCache.withCache { cache =>
3939
start(file, cache)

src/main/scala/module/RegenerateTileOrientationCache.scala

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.sc4nam.module
22

33
import java.io.File
44
import io.github.memo33.metarules.meta.RotFlip
5+
import syntax.RuleTransducer.TileOrientationCache
56

67
/** Manages the tile orientation cache. The cache is necessary to maintain
78
* information about non-standard orientations:
@@ -23,19 +24,24 @@ object RegenerateTileOrientationCache {
2324

2425
/** Repeatedly compiles the metarule code until the cache does not get changed anymore.
2526
*/
26-
def compileMetarulesUntilStable(tileOrientationCache: collection.mutable.Map[Int, Set[RotFlip]]): Unit = {
27+
def compileMetarulesUntilStable(cache: collection.mutable.Map[Int, Set[RotFlip]]): Unit = {
28+
val tileOrientationCache = TileOrientationCache(cache = cache, accum = collection.mutable.Map.empty[Int, Set[RotFlip]])
2729
var j = 0
2830
var stabilized = false
29-
var previous: collection.immutable.Map[Int, Set[RotFlip]] = tileOrientationCache.toMap
30-
while (j < 3 && !stabilized) {
31-
LOGGER.info(s"> metarules compilation: iteration $j")
31+
val maxIter = 5
32+
while (j < 5 && !stabilized) {
3233
j += 1
34+
LOGGER.info(s"> metarules compilation: iteration $j")
3335
CompileAllMetarules.compileMetarulesOnce(tileOrientationCache)
34-
val next = tileOrientationCache.toMap
35-
if (next == previous) {
36+
if (tileOrientationCache.accum.nonEmpty) {
37+
tileOrientationCache.cache ++= tileOrientationCache.accum
38+
tileOrientationCache.accum.clear()
39+
if (j == maxIter) {
40+
LOGGER.warning(s"Tile orientation cache could not be regenerated in $maxIter iterations. Increase the number of iterations or check if there is a bug.")
41+
}
42+
} else {
3643
stabilized = true
3744
}
38-
previous = next
3945
}
4046
}
4147

@@ -50,7 +56,7 @@ object RegenerateTileOrientationCache {
5056
}
5157
}
5258

53-
def loadCache(): collection.mutable.Map[Int, Set[RotFlip]] = {
59+
def loadCache(): TileOrientationCache = {
5460
scala.util.Using.resource(new java.util.Scanner(cacheFile, "UTF-8")) { scanner =>
5561
val cache = collection.mutable.Map.empty[Int, Set[RotFlip]]
5662
while(scanner.hasNextLine()) {
@@ -62,21 +68,18 @@ object RegenerateTileOrientationCache {
6268
cache(id) = orientations
6369
}
6470
}
65-
cache
71+
TileOrientationCache(cache = cache, accum = collection.mutable.Map.empty[Int, Set[RotFlip]])
6672
}
6773
}
6874

6975
/** Loads the cache and gives a warning at the end if it was changed.
7076
*/
71-
def withCache[U](body: collection.mutable.Map[Int, Set[RotFlip]] => U): U = {
72-
var previous: collection.immutable.Map[Int, Set[RotFlip]] = null
73-
val cache = loadCache()
77+
def withCache[U](body: TileOrientationCache => U): U = {
78+
val tileOrientationCache = loadCache()
7479
try {
75-
previous = cache.toMap
76-
body(cache)
80+
body(tileOrientationCache)
7781
} finally {
78-
assert(previous != null)
79-
if (previous != cache.toMap) {
82+
if (tileOrientationCache.accum.nonEmpty) {
8083
LOGGER.warning(s"The file ${cacheFile} is outdated. Rebuild it with `sbt regenerateTileOrientationCache` and commit the changes.")
8184
}
8285
}

src/test/scala/meta/RuleTransducerSpec.scala

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,20 @@ import RuleTransducer._
1010
class RuleTransducerSpec extends AnyWordSpec with Matchers {
1111

1212
val resolver = new module.RhwResolver orElse new module.NwmResolver orElse new module.MiscResolver
13-
val tileOrientationCache = collection.mutable.Map.empty[Int, Set[RotFlip]]
14-
val context = RuleTransducer.Context(resolver, tileOrientationCache, module.MirrorVariants.preprocessor)
13+
val context = RuleTransducer.Context(resolver, preprocess = module.MirrorVariants.preprocessor)
1514

1615
"preprocessor" should {
1716
"produce expected number of rules for Tla3" in {
1817
val orth: Seq[Rule[SymTile]] = context.preprocess( Tla3~WE | (Road ~> Tla3)~WE ).toSeq
1918
orth should have size (1)
2019
orth.asInstanceOf[Seq[Rule[Tile]]].exists(_.exists(_.segs.exists(s => s.flags.manifest == Flag.RightSpinBi && s.flags.exists(_ == 2)))) should be (false)
21-
createRules(orth.head.map(_.toIdSymTile(resolver)), tileOrientationCache).toSeq should have size (2)
20+
createRules(orth.head.map(_.toIdSymTile(resolver)), context.tileOrientationCache.cache, context.tileOrientationCache.accum).toSeq should have size (2)
2221

2322
context.preprocess( Tla3~WE & Road~NS | (Road ~> Tla3)~WE ).toSeq should have size (1)
2423
val diag = context.preprocess( Tla3~WE & Road~WS | (Road ~> Tla3)~WE ).toSeq
2524
diag should have size (2)
2625
for (r <- diag) {
27-
createRules(r.map(_.toIdSymTile(resolver)), tileOrientationCache).toSeq should have size (2)
26+
createRules(r.map(_.toIdSymTile(resolver)), context.tileOrientationCache.cache, context.tileOrientationCache.accum).toSeq should have size (2)
2827
}
2928
}
3029
}
@@ -53,7 +52,7 @@ class RuleTransducerSpec extends AnyWordSpec with Matchers {
5352
"find RHS for TLA" in {
5453
val rule = (Tla3~WE | (Road ~> Tla3)~(2,0,11,0)) map makeTileLeft map (_.toIdSymTile(resolver))
5554
possibleMapOrientation(Set(R0F0, R1F0), R3F0/R2F1, Quotient.Dih4, R1F1/R2F1) should not be (Symbol("empty"))
56-
createRules(rule, tileOrientationCache)
55+
createRules(rule, context.tileOrientationCache.cache, context.tileOrientationCache.accum)
5756
}
5857
"resolve diagonal TLA intersections" in {
5958
val t1 = makeTileLeft(Tla3~ES & Road~WS)

0 commit comments

Comments
 (0)