一个观察结果...在典型的使用中,您会发现sliding
方法是将数据输入自动机的最简单方法。它的工作原理是这样的:
scala> val input = Seq(1,2,3,4,5,6,7,8,9)
input: Seq[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9)
scala> input.sliding(3).toList
res4: List[Seq[Int]] =List(
List(1, 2, 3),
List(2, 3, 4),
...
List(6, 7, 8),
List(7, 8, 9))
为了确保序列输出由sliding
数量等于输入元素的数量,则需要垫两边的输入顺序:
scala> (0 +: input :+ 0).sliding(3).toList
res9: List[Seq[Int]] = List(
List(0, 1, 2),
List(1, 2, 3),
...
List(7, 8, 9),
List(8, 9, 0))
那么足够的理论,回到代码!
对于你的例子(因为我理解了一些潜在的问题),我在这里用false
值填充序列。
由于sliding
将输出序列而不是元组,我创建了seqYieldsTrue
辅助方法来处理翻译。我也改名rule
到apply
,让你的类可以直接用作功能:话又说回来
trait Rule {
def ruleId: Int //abstract
def yieldsTrue(input: (Boolean,Boolean,Boolean)): Boolean //abstract
override def toString: String = "Rule:" + ruleId
private def seqYieldsTrue(input: Seq[Boolean]) = {
assert(input.size == 3)
input match {
case Seq(a,b,c) => yieldsTrue((a,b,c))
case _ => error("invalid input size")
}
}
def apply(input: Seq[Boolean]) =
(false +: input :+ false).sliding(3) map { seqYieldsTrue }
}
class Rule90 extends Rule {
val ruleId = 90
val falsehoods = Seq(
(true, true, true),
(true, false, true),
(false, true, false),
(false, false, false)
)
def yieldsTrue(input: (Boolean,Boolean,Boolean)) = !falsehoods.contains(input)
}
,我没有说我明白了潜在的问题!所以,让刚刚废除所有这些繁琐的手动规则的定义,并让编译器生成很多关于我们:)
如果你不介意的一些位变换...
class WolframAutomata(val ruleId: Int) extends Rule {
def pow2(x: Int) = math.pow(2,x).toInt
def isBitSet(x: Int, bit: Int) = (x & pow2(bit)) > 0
// 8 possible input patterns corresponding to
// different combinations of 3 input bits
val inputs = (0 to 7) map { id =>
Tuple3(
isBitSet(id, 2),
isBitSet(id, 1),
isBitSet(id, 0)
) -> id
} toMap
//each of the 8 input rules corresponds to one bit in the ruleId
val outputs = inputs mapValues { isBitSet(ruleId, _) }
def yieldsTrue(input: (Boolean,Boolean,Boolean)) = outputs(input)
}
(从标识生成自动从这里采取的规则:)这样工作http://www.wolframscience.com/nksonline/page-53#previous
,您也可以滚动逻辑备份到规则特质,因为有一个单独的抽象特征没有必要,如果有就永远只能成为一个子类。在这种情况下,您也可以安全地取消yieldsTrue
,并直接使用val的output
。我会离开,作为一个练习留给读者......
全部放在一起(无用REPL输出线去掉):
scala> val r90 = new WolframAutomata(90)
r90: WolframAutomata = Rule:90
scala> def destringify(s:String) = s map { case 'X' => true; case _ => false } toSeq
scala> val input = destringify(".......X.......")
scala> val output = Iterator.iterate(input)(r90.apply(_).toSeq) toSeq
scala> def stringify(xs: Seq[Boolean]) = xs map {case true => "X"; case _ => "."} mkString
//can you see what it is yet?
scala> val sierpinski = output.take(10).map(stringify).mkString("\n")
sierpinski: String =
.......X.......
......X.X......
.....X...X.....
....X.X.X.X....
...X.......X...
..X.X.....X.X..
.X...X...X...X.
X.X.X.X.X.X.X.X
...............
...............
请原谅所有toSeq
电话,他们大多是到力评估,以便您可以在REPL上看到一些实际的输出,而不仅仅是non-empty iterator