|
1 package object abacus { |
|
2 |
|
3 import lib._ |
|
4 |
|
5 // Abacus machines |
|
6 sealed abstract class AInst |
|
7 case class Inc(n: Int) extends AInst |
|
8 case class Dec(n: Int, l: Int) extends AInst |
|
9 case class Goto(l: Int) extends AInst |
|
10 |
|
11 type AProg = List[AInst] |
|
12 type Regs = Map[Int, Int] |
|
13 |
|
14 case class AConfig(s: Int, regs: Regs) |
|
15 |
|
16 case class Abacus(p: AProg) { |
|
17 |
|
18 def ++ (that: Abacus) = Abacus(this.p ::: that.p) |
|
19 |
|
20 def shift(offset: Int, jump: Int) = Abacus(p.map(_ match { |
|
21 case Inc(n) => Inc(n) |
|
22 case Dec(n, l) => if (l == jump) Dec(n, l) else Dec(n, l + offset) |
|
23 case Goto(l) => if (l == jump) Goto(l) else Goto(l + offset) |
|
24 })) |
|
25 |
|
26 def adjust(old_jump: Int, jump: Int) = Abacus(p.map(_ match { |
|
27 case Inc(n) => Inc(n) |
|
28 case Dec(n, l) => if (l == old_jump) Dec(n, jump) else Dec(n, l) |
|
29 case Goto(l) => if (l == old_jump) Goto(jump) else Goto(l) |
|
30 })) |
|
31 |
|
32 def step(cf: AConfig) : AConfig = (nth_of(p, cf.s), cf.s) match { |
|
33 case (None, _) => cf |
|
34 case (Some(Inc(n)), s) => AConfig(s + 1, cf.regs + (n -> (dget(cf.regs, n) + 1))) |
|
35 case (Some(Dec(n, l)), s) => { |
|
36 if (dget(cf.regs, n) == 0) AConfig(l, cf.regs) |
|
37 else AConfig(s + 1, cf.regs + (n -> (dget(cf.regs, n) - 1))) |
|
38 } |
|
39 case (Some(Goto(l)), _) => AConfig(l, cf.regs) |
|
40 } |
|
41 |
|
42 def steps(cf: AConfig, n: Int) : AConfig = n match { |
|
43 case 0 => cf |
|
44 case n => steps(step(cf), n - 1) |
|
45 } |
|
46 |
|
47 def steps(regs: Regs, n: Int) : AConfig = steps(AConfig(0, regs), n) |
|
48 |
|
49 def run(cf: AConfig) : AConfig = { |
|
50 if (cf.s >= p.length || cf.s < 0) cf else run(step(cf)) |
|
51 } |
|
52 |
|
53 def run(regs: Regs): Regs = run(AConfig(0, regs)).regs |
|
54 } |
|
55 |
|
56 } |
|
57 |