Skip to content

Commit

Permalink
make loading of RHD/LHD rules more robust against duplicates or confl…
Browse files Browse the repository at this point in the history
…icts
  • Loading branch information
memo33 authored and jflann committed Jan 14, 2025
1 parent 7410e11 commit 9ac972a
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 19 deletions.
23 changes: 16 additions & 7 deletions src/main/scala/module/Rul2Model.scala
Original file line number Diff line number Diff line change
Expand Up @@ -102,13 +102,11 @@ object Rul2Model {
case Some((rule, RhdAndLhd)) =>
val key = new EquivRule(rule)
if (!rulesShared.contains(key)) {
if (!rulesRhd.contains(key) && !rulesLhd.contains(key))
rulesShared.addOne(key, rule)
else
require(
rulesRhd.contains(key) == rulesLhd.contains(key),
s"There's an unexpected rule conflict that differs between RHD and LHD: $rule"
)
(rulesRhd.get(key).filterNot(rulesHaveSameOutput(rule, _)), rulesLhd.get(key).filterNot(rulesHaveSameOutput(rule, _))) match {
case (None, None) => rulesShared.addOne(key, rule)
case (Some(rule2), Some(rule3)) => // ignore, as both RHD/LHD already define a different rule, so this rule never has an effect
case _ => require(false, s"There's an unexpected rule conflict that differs between RHD and LHD: $rule")
}
}
case None => // ignore
}
Expand All @@ -124,6 +122,17 @@ object Rul2Model {
lookupRule.unapply(key).flatMap(rule => applyRule(rule, t0, t1))
}

/** Check if two rules with equivalent LHS actually lead to the same output on
* the RHS (and thus are not at conflict with each other).
*/
def rulesHaveSameOutput(x: Rule[IdTile], y: Rule[IdTile]): Boolean = (
x(0) == y(0) && x(1) == y(1) && x(2) == y(2) && x(3) == y(3) ||
x(0) == y(0) * R2F1 && x(1) == y(1) * R2F1 && x(2) == y(2) * R2F1 && x(3) == y(3) * R2F1 ||
x(0) == y(1) * R2F0 && x(1) == y(0) * R2F0 && x(2) == y(3) * R2F0 && x(3) == y(2) * R2F0 ||
x(0) == y(1) * R0F1 && x(1) == y(0) * R0F1 && x(2) == y(3) * R0F1 && x(3) == y(2) * R0F1 ||
(x(2).id == 0 || x(3).id == 0) && (y(2).id == 0 || y(3).id == 0)
)

}

/** Holds all RUL2 code in memory. Instantiate this with `Rul2Model.load`. */
Expand Down
13 changes: 1 addition & 12 deletions src/main/scala/scripts/ConflictingOverridesChecker.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import java.nio.file.{Files, Paths}
import io.github.memo33.metarules.meta.{RotFlip, EquivRule, Rule, IdTile}
import RotFlip._
import com.sc4nam.module._
import Rul2Model.{iterateRulFiles, parseRuleWithRestrictedDriveside, Driveside, Rhd, Lhd, RhdAndLhd, drivesideOfFile}
import Rul2Model.{iterateRulFiles, parseRuleWithRestrictedDriveside, Driveside, Rhd, Lhd, RhdAndLhd, drivesideOfFile, rulesHaveSameOutput}
import SanityChecker.{fileEndsWithNewline, linePatternIncludingNewlines}

/** Checks for conflicting/duplicate RUL2 code. There are two modes of operation:
Expand Down Expand Up @@ -183,15 +183,4 @@ object ConflictingOverridesChecker {
if (add.isDefined) s"$line0; ${add.get}" else line0
}

/** Check if two rules with equivalent LHS actually lead to the same output on
* the RHS (and thus are not at conflict with each other).
*/
def rulesHaveSameOutput(x: Rule[IdTile], y: Rule[IdTile]): Boolean = (
x(0) == y(0) && x(1) == y(1) && x(2) == y(2) && x(3) == y(3) ||
x(0) == y(0) * R2F1 && x(1) == y(1) * R2F1 && x(2) == y(2) * R2F1 && x(3) == y(3) * R2F1 ||
x(0) == y(1) * R2F0 && x(1) == y(0) * R2F0 && x(2) == y(3) * R2F0 && x(3) == y(2) * R2F0 ||
x(0) == y(1) * R0F1 && x(1) == y(0) * R0F1 && x(2) == y(3) * R0F1 && x(3) == y(2) * R0F1 ||
(x(2).id == 0 || x(3).id == 0) && (y(2).id == 0 || y(3).id == 0)
)

}

0 comments on commit 9ac972a

Please sign in to comment.