Skip to content

Commit

Permalink
Revamp implement of rule ranges
Browse files Browse the repository at this point in the history
  • Loading branch information
jedlimlx committed May 22, 2024
1 parent c68752b commit e7611e3
Show file tree
Hide file tree
Showing 23 changed files with 183 additions and 302 deletions.
2 changes: 1 addition & 1 deletion src/commonMain/kotlin/LRUCache.kt
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ class LRUCache<K, V>(

override fun put(key: K, value: V): V? {
if (key in map) remove(key)
if (map.size > maxSize) remove(head!!.value.first)
if (map.size > maxSize - 1) remove(head!!.value.first)

val node = Node(Pair(key, value), tail, null)
if (head == null) head = node
Expand Down
9 changes: 8 additions & 1 deletion src/commonMain/kotlin/patterns/Pattern.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package patterns

import rules.PLACEHOLDER_RULE
import rules.Rule
import rules.RuleRange

/**
* Represents a special pattern in cellular automaton
Expand All @@ -16,10 +18,15 @@ abstract class Pattern {
*/
open var discoverer: String = ""

/**
* The rule the pattern can be found in
*/
abstract val rule: Rule

/**
* The rule range in which the pattern functions
*/
open val ruleRange: Pair<Rule, Rule>? = null
open val ruleRange: RuleRange<*>? = null

/**
* Some information about the pattern to display
Expand Down
14 changes: 5 additions & 9 deletions src/commonMain/kotlin/patterns/Spaceship.kt
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
package patterns

import rules.Rule
import rules.RuleFamily
import rules.fromRulestring
import rules.ruleRange
import rules.*
import simulation.Coordinate
import simulation.Grid
import simulation.DenseGrid
import simulation.SparseGrid
import simulation.Rotation
import simulation.Flip
Expand Down Expand Up @@ -50,7 +46,7 @@ open class Spaceship(val dx: Int, val dy: Int, val period: Int, val phases: Arra
/**
* The rule that the spaceship operates in
*/
val rule = phases[0].rule
override val rule = phases[0].rule

/**
* The spaceship's speed formatted properly as a string
Expand Down Expand Up @@ -123,7 +119,7 @@ open class Spaceship(val dx: Int, val dy: Int, val period: Int, val phases: Arra
* (only works if the spaceship operates in an isotropic rule)
*/
open val canonPhase by lazy {
var output = smallestPhase.deepCopy()
val output = smallestPhase.deepCopy()

// Orienting the spaceship to go in the north-west direction
var dx = dx
Expand Down Expand Up @@ -159,7 +155,7 @@ open class Spaceship(val dx: Int, val dy: Int, val period: Int, val phases: Arra
open val gliderdbEntry by lazy {
canonPhase.updateBounds()
val size = canonPhase.bounds.endInclusive - canonPhase.bounds.start
"$name:$discoverer:${ruleRange!!.first}:${ruleRange!!.second}:$period:${size.x}:${size.y}:${minOf(abs(dx),abs(dy))}:${maxOf(abs(dx),abs(dy))}:$canonPhase"
"$name:$discoverer:${ruleRange!!.minRule}:${ruleRange!!.maxRule}:$period:${size.x}:${size.y}:${minOf(abs(dx),abs(dy))}:${maxOf(abs(dx),abs(dy))}:$canonPhase"
}

override val information: Map<String, String> by lazy {
Expand All @@ -178,7 +174,7 @@ open class Spaceship(val dx: Int, val dy: Int, val period: Int, val phases: Arra
map
}

override val ruleRange: Pair<Rule, Rule>? by lazy {
override val ruleRange: RuleRange<*>? by lazy {
val newPhases = phases.toMutableList()
newPhases.add(newPhases[newPhases.size - 1].deepCopy().step())

Expand Down
18 changes: 9 additions & 9 deletions src/commonMain/kotlin/patterns/gliderdb/GliderDB.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ import patterns.fromGliderDBEntry

import kotlin.math.abs

import rules.Rule
import rules.RuleFamily
import rules.RuleRange
import rules.RuleRangeable

/**
* Represents a database of gliders (spaceships) / oscillators.
* @param lst A list of spaceships to initialise the database with.
*/
class GliderDB(lst: List<Spaceship>): PatternCollection<Spaceship>() {
class GliderDB<R>(lst: List<Spaceship>): PatternCollection<Spaceship>() where R : RuleFamily, R : RuleRangeable<R> {
val lst = ArrayList(lst)

/**
Expand Down Expand Up @@ -59,7 +59,7 @@ class GliderDB(lst: List<Spaceship>): PatternCollection<Spaceship>() {
* Searches for spaceships moving at ([dx], [dy])c/[period].
* @param higher_periods Should ships of the same speed but higher period be returned?
*/
fun searchBySpeed(dx: Int, dy: Int, period: Int, higherPeriod: Boolean = false): GliderDB {
fun searchBySpeed(dx: Int, dy: Int, period: Int, higherPeriod: Boolean = false): GliderDB<R> {
if (higherPeriod) {
return GliderDB(
this.filter {
Expand All @@ -77,13 +77,13 @@ class GliderDB(lst: List<Spaceship>): PatternCollection<Spaceship>() {
}
}

fun searchBySpeed(speed: String, higherPeriod: Boolean = false): GliderDB {
fun searchBySpeed(speed: String, higherPeriod: Boolean = false): GliderDB<R> {
val (displacement, period) = parseSpeed(speed)
val (dx, dy) = displacement
return searchBySpeed(dx, dy, period, higherPeriod)
}

fun searchBySlope(dx: Int, dy: Int): GliderDB {
fun searchBySlope(dx: Int, dy: Int): GliderDB<R> {
require(dx != 0 || dy != 0) { "(0, 0) is not a valid slope." }
return GliderDB(
this.filter {
Expand All @@ -94,13 +94,13 @@ class GliderDB(lst: List<Spaceship>): PatternCollection<Spaceship>() {
)
}

fun searchByRule(rule: RuleFamily) = GliderDB(
this.filter { rule in (it.ruleRange!!.first as RuleFamily) .. (it.ruleRange!!.second as RuleFamily) }
fun searchByRule(rule: RuleFamily) = GliderDB<R>(
this.filter { rule in it.ruleRange!! }
)

fun searchByRule(ruleRange: RuleRange) = GliderDB(
fun searchByRule(ruleRange: RuleRange<R>) = GliderDB<R>(
this.filter {
ruleRange intersect ((it.ruleRange!!.first as RuleFamily) .. (it.ruleRange!!.second as RuleFamily)) != null
ruleRange intersect (it.ruleRange!! as RuleRange<R>) != null
}
)

Expand Down
46 changes: 0 additions & 46 deletions src/commonMain/kotlin/rules/RuleFamily.kt
Original file line number Diff line number Diff line change
Expand Up @@ -30,52 +30,6 @@ abstract class RuleFamily : Rule() {
*/
internal abstract fun fromRulestring(rulestring: String): RuleFamily

/**
* Checks if a rule is between 2 other rules
* @param minRule The minimum rule
* @param maxRule The maximum rule
* @return Returns true if the rule is between the two rules, false otherwise
*/
internal abstract fun between(minRule: RuleFamily, maxRule: RuleFamily): Boolean

/**
* The range of rules in which the provided transitions will occur
* TODO why does this return a pair instead of a RuleRange object
* @return Returns a pair of rules, the first is the minimum rule and the second is the maximum rule
*/
internal abstract fun ruleRange(transitionsToSatisfy: Iterable<List<Int>>): Pair<RuleFamily, RuleFamily>

/**
* Outputs a sequence containing all rules within the specified rule range
* @param minRule The minimum rule of the rule range
* @param maxRule The maximum rule of the rule range
* @return Returns a sequence containing all rules within the specified rule range
*/
internal abstract fun enumerate(minRule: RuleFamily, maxRule: RuleFamily): Sequence<RuleFamily>

/**
* Outputs an infinite sequence of random rules within the specified rule range
* @param minRule The minimum rule of the rule range
* @param maxRule The maximum rule of the rule range
* @return Returns an infinite sequence of random rules
*/
internal abstract fun random(minRule: RuleFamily, maxRule: RuleFamily, seed: Int? = null): Sequence<RuleFamily>

/**
* Computes the intersection between [ruleRange1] and [ruleRange2]
* @param ruleRange1 One rule range to use in the intersection
* @param ruleRange2 The other rule range to use in the intersection
* @return A new rule range containining the rules in both [ruleRange1] and [ruleRange2]. Returns null if no intersection.
*/
internal abstract fun intersect(ruleRange1: RuleRange, ruleRange2: RuleRange): RuleRange?

/**
* Outputs a sequence containing all rules within the specified rule range
* @param maxRule The maximum rule of the rule range
* @return Returns a sequence containing all rules within the specified rule range
*/
operator fun rangeTo(maxRule: RuleFamily): RuleRange = RuleRange(this, maxRule)

/**
* Generates a ruletable for the rule which can be used in Golly / Apgsearch
* @return Returns the ruletable
Expand Down
7 changes: 4 additions & 3 deletions src/commonMain/kotlin/rules/RuleRange.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ package rules
/**
* Represents a range of rules between the minimum and maximum rules
*/
class RuleRange(val minRule: RuleFamily, val maxRule: RuleFamily): Sequence<RuleFamily> {
class RuleRange<R>(val minRule: R, val maxRule: R) : Sequence<RuleFamily>
where R : RuleFamily, R : RuleRangeable<R> {
private val enumerationIterator = minRule.enumerate(minRule, maxRule).iterator()

/**
Expand All @@ -25,14 +26,14 @@ class RuleRange(val minRule: RuleFamily, val maxRule: RuleFamily): Sequence<Rule
* @param ruleFamily The rule to check
* @return Returns true if the rule is within the rule range, false otherwise
*/
operator fun contains(ruleFamily: RuleFamily): Boolean = ruleFamily.between(minRule, maxRule)
operator fun contains(ruleFamily: R): Boolean = ruleFamily.between(minRule, maxRule)

/**
* Computes the intersection between 2 rule ranges
* @param ruleRange The other rule range to compute the intersection with
* @return Returns the intersection between the 2 rule ranges
*/
infix fun intersect(ruleRange: RuleRange): RuleRange? = minRule.intersect(this, ruleRange)
infix fun intersect(ruleRange: RuleRange<R>): RuleRange<R>? = minRule.intersect(this, ruleRange)

override fun iterator(): Iterator<RuleFamily> = enumerationIterator
}
48 changes: 48 additions & 0 deletions src/commonMain/kotlin/rules/RuleRangeable.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package rules

interface RuleRangeable<R> where R : RuleFamily, R : RuleRangeable<R> {
/**
* Checks if a rule is between 2 other rules
* @param minRule The minimum rule
* @param maxRule The maximum rule
* @return Returns true if the rule is between the two rules, false otherwise
*/
fun between(minRule: R, maxRule: R): Boolean

/**
* The range of rules in which the provided transitions will occur
* @return Returns a pair of rules, the first is the minimum rule and the second is the maximum rule
*/
fun ruleRange(transitionsToSatisfy: Iterable<List<Int>>): RuleRange<R>

/**
* Outputs a sequence containing all rules within the specified rule range
* @param minRule The minimum rule of the rule range
* @param maxRule The maximum rule of the rule range
* @return Returns a sequence containing all rules within the specified rule range
*/
fun enumerate(minRule: R, maxRule: R): Sequence<R>

/**
* Outputs an infinite sequence of random rules within the specified rule range
* @param minRule The minimum rule of the rule range
* @param maxRule The maximum rule of the rule range
* @return Returns an infinite sequence of random rules
*/
fun random(minRule: R, maxRule: R, seed: Int? = null): Sequence<R>

/**
* Computes the intersection between [ruleRange1] and [ruleRange2]
* @param ruleRange1 One rule range to use in the intersection
* @param ruleRange2 The other rule range to use in the intersection
* @return A new rule range containining the rules in both [ruleRange1] and [ruleRange2]. Returns null if no intersection.
*/
fun intersect(ruleRange1: RuleRange<R>, ruleRange2: RuleRange<R>): RuleRange<R>?

/**
* Outputs a sequence containing all rules within the specified rule range
* @param maxRule The maximum rule of the rule range
* @return Returns a sequence containing all rules within the specified rule range
*/
operator fun rangeTo(maxRule: R): RuleRange<R>
}
27 changes: 19 additions & 8 deletions src/commonMain/kotlin/rules/RuleUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,19 @@ package rules
import rules.hrot.HROT
import rules.hrot.HROTGenerations
import rules.hrot.HROTExtendedGenerations
import rules.nontotalistic.rules.DeficientINT
import rules.nontotalistic.rules.INT
import rules.nontotalistic.rules.INTGenerations
import simulation.Grid

private val RULE_FAMILIES = listOf(HROT(), HROTGenerations(), HROTExtendedGenerations(), INT())
private val RULE_FAMILIES = listOf(
HROT(),
HROTGenerations(),
HROTExtendedGenerations(),
INT(),
INTGenerations(),
DeficientINT()
)

/**
* Creates a rule given its rulestring
Expand All @@ -27,7 +36,7 @@ fun fromRulestring(rulestring: String): RuleFamily {
* The range of rules in which the provided evolution of patterns works in
* @return Returns a pair of rules, the first is the minimum rule and the second is the maximum rule
*/
fun ruleRange(phases: List<Grid>): Pair<RuleFamily, RuleFamily> {
fun ruleRange(phases: List<Grid>): RuleRange<*> {
// Obtain the transitions at the min and max rule must satisfy
val transitionsToSatisfy = HashSet<List<Int>>(phases.fold(0) { acc, value -> acc + value.population })
for (i in 0 until phases.size - 1) {
Expand All @@ -52,23 +61,25 @@ fun ruleRange(phases: List<Grid>): Pair<RuleFamily, RuleFamily> {
}
}

require(phases[0].rule is RuleFamily) { "Rule of the specified pattern does not support rule range" }
return (phases[0].rule as RuleFamily).ruleRange(transitionsToSatisfy)
require(phases[0].rule is RuleFamily && phases[0].rule is RuleRangeable<*>) {
"Rule of the specified pattern does not support rule range"
}
return (phases[0].rule as RuleRangeable<*>).ruleRange(transitionsToSatisfy)
}

/**
* The range of rules in which the provided evolution of patterns works in
* @return Returns a pair of rules, the first is the minimum rule and the second is the maximum rule
*/
fun ruleRange(phases: Array<Grid>): Pair<RuleFamily, RuleFamily> = ruleRange(phases.toList())
fun ruleRange(phases: Array<Grid>): RuleRange<*> = ruleRange(phases.toList())

/**
* The range of rules in which the provided evolution of patterns works in
* @param minRule The minimum rule of the rule range to enumerate
* @param maxRule The maximum rule of the rule range to enumerate
* @return Returns a sequence of all rules within the rule range
*/
fun enumerateRules(minRule: RuleFamily, maxRule: RuleFamily): Sequence<RuleFamily> {
fun <R> enumerateRules(minRule: R, maxRule: R): Sequence<R> where R : RuleFamily, R : RuleRangeable<R> {
return minRule.enumerate(minRule, maxRule)
}

Expand All @@ -78,7 +89,7 @@ fun enumerateRules(minRule: RuleFamily, maxRule: RuleFamily): Sequence<RuleFamil
* @param maxRule The maximum rule of the rule range to enumerate
* @return Returns an infinite sequence of random rules within the rule range
*/
fun randomRules(minRule: RuleFamily, maxRule: RuleFamily, seed: Int? = null): Sequence<RuleFamily> {
fun <R> randomRules(minRule: R, maxRule: R, seed: Int? = null): Sequence<R> where R : RuleFamily, R : RuleRangeable<R> {
return minRule.random(minRule, maxRule, seed)
}

Expand All @@ -88,6 +99,6 @@ fun randomRules(minRule: RuleFamily, maxRule: RuleFamily, seed: Int? = null): Se
* @param maxRule The maximum rule of the rule range to enumerate
* @return Returns a random rule within the rule range
*/
fun randomRule(minRule: RuleFamily, maxRule: RuleFamily, seed: Int? = null): RuleFamily {
fun <R> randomRule(minRule: R, maxRule: R, seed: Int? = null): R where R : RuleFamily, R : RuleRangeable<R> {
return minRule.random(minRule, maxRule, seed).take(1).toList()[0]
}
Loading

0 comments on commit e7611e3

Please sign in to comment.