scala/abacus.scala
changeset 193 317a2532c567
child 194 fc2a5e9fbb97
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scala/abacus.scala	Thu Feb 21 16:07:40 2013 +0000
@@ -0,0 +1,57 @@
+package object abacus {
+
+import lib._
+
+// Abacus machines
+sealed abstract class AInst 
+case class Inc(n: Int) extends AInst
+case class Dec(n: Int, l: Int) extends AInst
+case class Goto(l: Int) extends AInst
+
+type AProg = List[AInst]
+type Regs = Map[Int, Int]
+
+case class AConfig(s: Int, regs: Regs)  
+
+case class Abacus(p: AProg) {
+
+  def ++ (that: Abacus) = Abacus(this.p ::: that.p)
+
+  def shift(offset: Int, jump: Int) = Abacus(p.map(_ match {
+    case Inc(n) => Inc(n)
+    case Dec(n, l) => if (l == jump) Dec(n, l) else Dec(n, l + offset)
+    case Goto(l) => if (l == jump) Goto(l) else Goto(l + offset)
+  }))
+      
+  def adjust(old_jump: Int, jump: Int) = Abacus(p.map(_ match {
+    case Inc(n) => Inc(n)
+    case Dec(n, l) => if (l == old_jump) Dec(n, jump) else Dec(n, l)
+    case Goto(l) => if (l == old_jump) Goto(jump) else Goto(l)
+  }))
+
+  def step(cf: AConfig) : AConfig = (nth_of(p, cf.s), cf.s) match {
+    case (None, _) => cf
+    case (Some(Inc(n)), s) => AConfig(s + 1, cf.regs + (n -> (dget(cf.regs, n) + 1)))
+    case (Some(Dec(n, l)), s) => {
+      if (dget(cf.regs, n) == 0) AConfig(l, cf.regs)
+      else AConfig(s + 1, cf.regs + (n -> (dget(cf.regs, n) - 1)))
+    }
+    case (Some(Goto(l)), _) => AConfig(l, cf.regs)
+  }  
+
+  def steps(cf: AConfig, n: Int) : AConfig = n match {
+    case 0 => cf
+    case n => steps(step(cf), n - 1)
+  } 
+
+  def steps(regs: Regs, n: Int) : AConfig = steps(AConfig(0, regs), n)
+
+  def run(cf: AConfig) : AConfig = {
+    if (cf.s >= p.length || cf.s < 0) cf else run(step(cf))
+  }
+ 
+  def run(regs: Regs): Regs = run(AConfig(0, regs)).regs
+}
+
+}
+