@@ -5,7 +5,8 @@ import com.sc4nam.module._
55import io .github .memo33 .metarules .meta .{RotFlip , Rule , EquivRule , IdTile }
66import RotFlip ._
77import syntax .IdTile
8- import SanityChecker .{isRulFile , fileEndsWithNewline , Driveside , Rhd , Lhd , RhdAndLhd , parseRule , linePatternIncludingNewlines }
8+ import SanityChecker .{fileEndsWithNewline , linePatternIncludingNewlines }
9+ import Rul2Model .{iterateRulFiles , parseRuleWithRestrictedDriveside , Rhd , Lhd , RhdAndLhd , drivesideOfFile , applyRule }
910
1011/** Run with `SBT_OPTS="-Xmx2G" sbt "runMain com.sc4nam.scripts.RedundantAdjacenciesChecker"`.
1112 * Note that this increases the heap size for more memory.
@@ -25,57 +26,13 @@ object RedundantAdjacenciesChecker {
2526 * redundant code.
2627 */
2728 def main (args : Array [String ]): Unit = {
28- checkRedundantAdjacencies()
29+ val rul2 = Rul2Model .load(Paths .get(" Controller/RUL2" ))
30+ checkRedundantAdjacencies(rul2)
2931 }
3032
31- def drivesideOfFile (path : Path ): Driveside = {
32- val name = path.getFileName().toString()
33- if (name.contains(" rhd." )) Rhd
34- else if (name.contains(" lhd." )) Lhd
35- else RhdAndLhd
36- }
37-
38- val lhdPrefix = " ;###LHD###"
39- val rhdPrefix = " ;###RHD###"
40-
41- def parseRuleWithRestrictedDriveside (line : String , driveside : Driveside ): Option [(Rule [IdTile ], Driveside )] = {
42- val line1 = line.trim()
43- if (line1.startsWith(lhdPrefix)) {
44- if (driveside == Rhd ) None else parseRule(line1.substring(lhdPrefix.length)).map(_ -> Lhd )
45- } else if (line1.startsWith(rhdPrefix)) {
46- if (driveside == Lhd ) None else parseRule(line1.substring(rhdPrefix.length)).map(_ -> Rhd )
47- } else {
48- parseRule(line1).map(_ -> driveside)
49- }
50- }
51-
52- def checkRedundantAdjacencies (): Unit = {
53- val rulesRhd = collection.mutable.Map .empty[EquivRule , Rule [IdTile ]]
54- val rulesLhd = collection.mutable.Map .empty[EquivRule , Rule [IdTile ]]
55- val rulesShared = collection.mutable.Map .empty[EquivRule , Rule [IdTile ]]
56- val lookupRuleRhd : PartialFunction [EquivRule , Rule [IdTile ]] = rulesShared.orElse(rulesRhd) // the two maps should be disjoint
57- val lookupRuleLhd : PartialFunction [EquivRule , Rule [IdTile ]] = rulesShared.orElse(rulesRhd) // the two maps should be disjoint
58-
59- LOGGER .info(" caching all RUL2 code for RHD and LHD" )
60- Files .walk(Paths .get(" Controller/RUL2" )).forEach { path =>
61- if (isRulFile(path)) {
62- val drivesideFile = drivesideOfFile(path)
63- scala.util.Using .resource(new java.util.Scanner (path.toFile(), " UTF-8" )) { scanner =>
64- while (scanner.hasNextLine()) {
65- parseRuleWithRestrictedDriveside(scanner.nextLine(), drivesideFile) match {
66- case Some ((rule, Rhd )) => rulesRhd.addOne(new EquivRule (rule), rule)
67- case Some ((rule, Lhd )) => rulesLhd.addOne(new EquivRule (rule), rule)
68- case Some ((rule, RhdAndLhd )) => rulesShared.addOne(new EquivRule (rule), rule)
69- case None => // ignore
70- }
71- }
72- }
73- }
74- }
75-
76- LOGGER .info(" searching for redundant adjacencies in RUL2 code" )
77- Files .walk(Paths .get(" Controller/RUL2" )).forEach { path =>
78- if (isRulFile(path)) {
33+ def checkRedundantAdjacencies (rul2 : Rul2Model ): Unit = {
34+ LOGGER .info(" Searching for redundant adjacencies in RUL2 code" )
35+ iterateRulFiles(Paths .get(" Controller/RUL2" )).foreach { path =>
7936 val drivesideFile = drivesideOfFile(path)
8037 val tmpPath = path.resolveSibling(path.getFileName().toString() + " .tmp" )
8138 val endsWithNewline = fileEndsWithNewline(path) // attempt to preserve missing newlines at end of files to avoid noise
@@ -88,13 +45,14 @@ object RedundantAdjacenciesChecker {
8845
8946 val redundant =
9047 parseRuleWithRestrictedDriveside(line, drivesideFile) match {
91- case Some ((rule, Rhd )) => isRedundantAdjacency(rule, lookupRuleRhd)
92- case Some ((rule, Lhd )) => isRedundantAdjacency(rule, lookupRuleLhd)
48+ case Some ((rule, Rhd )) => isRedundantAdjacency(rule, rul2. lookupRuleRhd)
49+ case Some ((rule, Lhd )) => isRedundantAdjacency(rule, rul2. lookupRuleLhd)
9350 case Some ((rule, RhdAndLhd )) =>
94- val b = isRedundantAdjacency(rule, lookupRuleRhd)
95- if (b != isRedundantAdjacency(rule, lookupRuleLhd)) {
96- throw new AssertionError (" Redundancies should be the same for RHD and LHD." ) // hopefully this will always be the case
97- }
51+ val b = isRedundantAdjacency(rule, rul2.lookupRuleRhd)
52+ require(
53+ b == isRedundantAdjacency(rule, rul2.lookupRuleLhd),
54+ s " Redundancies should be the same for RHD and LHD: $rule" // hopefully this will always be the case
55+ )
9856 b
9957 case None => false // comments are not redundant
10058 }
@@ -107,7 +65,6 @@ object RedundantAdjacenciesChecker {
10765 }
10866 }
10967 Files .move(tmpPath, path, java.nio.file.StandardCopyOption .REPLACE_EXISTING )
110- }
11168 }
11269 }
11370
@@ -139,27 +96,14 @@ object RedundantAdjacenciesChecker {
13996 (a * rot, b * rot, southBound)
14097 }}
14198
142- def evaluateRule (rule : Rule [IdTile ], t0 : IdTile , t1 : IdTile ): Option [(IdTile , IdTile )] = {
143- if (t0 == rule(0 ) && t1 == rule(1 )) Some ((rule(2 ), rule(3 )))
144- else if (t0 == rule(0 ) * R2F1 && t1 == rule(1 ) * R2F1 ) Some ((rule(2 ) * R2F1 , rule(3 ) * R2F1 ))
145- else if (t0 == rule(1 ) * R0F1 && t1 == rule(0 ) * R0F1 ) Some ((rule(3 ) * R0F1 , rule(2 ) * R0F1 ))
146- else if (t0 == rule(1 ) * R2F0 && t1 == rule(0 ) * R2F0 ) Some ((rule(3 ) * R2F0 , rule(2 ) * R2F0 ))
147- else None
148- }
149-
150- def evaluateRulesOnce (lookupRule : PartialFunction [EquivRule , Rule [IdTile ]], t0 : IdTile , t1 : IdTile ): Option [(IdTile , IdTile )] = {
151- val key = new EquivRule (Rule (t0, t1, t0, t1))
152- lookupRule.unapply(key).flatMap(rule => evaluateRule(rule, t0, t1))
153- }
154-
15599 /** Checks if adjacency overrides a -> b and b -> c exist (in that order and
156100 * direction) (where b is surrogate tile) and matches expected result
157101 * aExpected, cExpected.
158102 */
159103 def connectingOrthOverridesExist (lookupRule : PartialFunction [EquivRule , Rule [IdTile ]], a : IdTile , b : IdTile , c : IdTile , aExpected : IdTile , cExpected : IdTile ): Boolean = {
160- evaluateRulesOnce(lookupRule, a, b) match {
104+ Rul2Model . evaluateRulesOnce(lookupRule, a, b) match {
161105 case Some ((a1, b1)) if a1 == a && a1.id != b1.id =>
162- evaluateRulesOnce(lookupRule, b1, c) match {
106+ Rul2Model . evaluateRulesOnce(lookupRule, b1, c) match {
163107 case Some ((b2, c2)) if b2 == b1 && b2.id != c2.id && c2 != c =>
164108 // found two overrides connecting a to c, so check if result of their application is as expected
165109 a1 == aExpected && c2 == cExpected
@@ -175,15 +119,15 @@ object RedundantAdjacenciesChecker {
175119 * northbound direction.
176120 */
177121 def connectingDiagOverridesExist (lookupRule : PartialFunction [EquivRule , Rule [IdTile ]], a : IdTile , b : IdTile , c : IdTile , d : IdTile , southBound : Boolean , aExpected : IdTile , dExpected : IdTile ): Boolean = {
178- evaluateRulesOnce(lookupRule, a, b) match {
122+ Rul2Model . evaluateRulesOnce(lookupRule, a, b) match {
179123 case Some ((a1, b1)) if a1 == a && a1.id != b1.id =>
180124 val rot = if (southBound) R3F0 else R1F0
181- evaluateRulesOnce(lookupRule, b1 * rot, c * rot) match {
125+ Rul2Model . evaluateRulesOnce(lookupRule, b1 * rot, c * rot) match {
182126 case Some ((b2rot, c2rot)) =>
183127 val b2 = b2rot * (R0F0 / rot)
184128 val c2 = c2rot * (R0F0 / rot)
185129 if (b2 == b1 && c2 != c) {
186- evaluateRulesOnce(lookupRule, c2, d) match {
130+ Rul2Model . evaluateRulesOnce(lookupRule, c2, d) match {
187131 case Some ((c3, d3)) if c3 == c2 && d3.id != c3.id && d3.id != b2.id && d3 != d =>
188132 a1 == aExpected && d3 == dExpected
189133 case _ => false
0 commit comments