|         |      1 // 2 x 2 x 2 Rubik's Cube | 
|         |      2 //======================== | 
|         |      3  | 
|         |      4 // for more memory for the JVM, call | 
|         |      5 // | 
|         |      6 // JAVA_OPTS="-Xmx2g" scala | 
|         |      7  | 
|         |      8  | 
|         |      9 // for measuring memory usage | 
|         |     10 val mb = 1024*1024 | 
|         |     11 val runtime = Runtime.getRuntime | 
|         |     12  | 
|         |     13 def memory() = { | 
|         |     14   println(s"  ** Used Memory:  ${(runtime.totalMemory - runtime.freeMemory) / mb}") | 
|         |     15   println(s"  ** Free Memory:  ${runtime.freeMemory / mb}") | 
|         |     16   println(s"  ** Total Memory: ${runtime.totalMemory / mb}") | 
|         |     17   println(s"  ** Max Memory:   ${runtime.maxMemory / mb}") | 
|         |     18 } | 
|         |     19  | 
|         |     20  | 
|         |     21 abstract class Colour | 
|         |     22 case object White extends Colour | 
|         |     23 case object Yellow extends Colour | 
|         |     24 case object Orange extends Colour | 
|         |     25 case object Red extends Colour | 
|         |     26 case object Green extends Colour | 
|         |     27 case object Blue extends Colour | 
|         |     28  | 
|         |     29 // Faces | 
|         |     30 //    ------- | 
|         |     31 //   |c11 c12| | 
|         |     32 //   |c21 c22| | 
|         |     33 //    -------   | 
|         |     34 case class Face(c11: Colour, c12: Colour, | 
|         |     35                 c21: Colour, c22: Colour) | 
|         |     36  | 
|         |     37  | 
|         |     38 // Cubes | 
|         |     39 //     +--+ | 
|         |     40 //     |f2| | 
|         |     41 //  +--+  +--+ | 
|         |     42 //  |f5 f1 f6| | 
|         |     43 //  +--+  +--+ | 
|         |     44 //     |f3| | 
|         |     45 //     |f4| | 
|         |     46 //     +--+  | 
|         |     47 case class Cube(f1: Face, f2: Face, f3: Face, | 
|         |     48                 f4: Face, f5: Face, f6: Face) | 
|         |     49  | 
|         |     50  | 
|         |     51 // starting cube | 
|         |     52 val init =  | 
|         |     53     Cube(Face(White, Green, White, White),  | 
|         |     54          Face(Blue, Yellow, Orange, Red),  | 
|         |     55          Face(Red, Blue, Red, Blue), | 
|         |     56          Face(White, Yellow, Red, Orange), | 
|         |     57          Face(Yellow, Green, Blue, Green), | 
|         |     58          Face(Yellow, Green, Orange, Orange)) | 
|         |     59  | 
|         |     60 // solved cube | 
|         |     61 val solved =  | 
|         |     62     Cube(Face(Yellow, Yellow, Yellow, Yellow),  | 
|         |     63          Face(Orange, Orange, Orange, Orange),  | 
|         |     64          Face(Red, Red, Red, Red), | 
|         |     65          Face(White, White, White, White), | 
|         |     66          Face(Blue, Blue, Blue, Blue), | 
|         |     67          Face(Green, Green, Green, Green))   | 
|         |     68  | 
|         |     69  | 
|         |     70  | 
|         |     71 // actions | 
|         |     72 def up(c: Cube) : Cube = | 
|         |     73     Cube(Face(c.f1.c11, c.f3.c12, c.f1.c21, c.f3.c22), | 
|         |     74          Face(c.f2.c11, c.f1.c12, c.f2.c21, c.f1.c22), | 
|         |     75          Face(c.f3.c11, c.f4.c12, c.f3.c21, c.f4.c22), | 
|         |     76          Face(c.f4.c11, c.f2.c12, c.f4.c21, c.f2.c22), | 
|         |     77          Face(c.f5.c11, c.f5.c12, c.f5.c21, c.f5.c22), | 
|         |     78          Face(c.f6.c21, c.f6.c11, c.f6.c22, c.f6.c12)) | 
|         |     79  | 
|         |     80 def clock(c: Cube) : Cube = | 
|         |     81     Cube(Face(c.f1.c21, c.f1.c11, c.f1.c22, c.f1.c12), | 
|         |     82          Face(c.f2.c11, c.f2.c12, c.f5.c22, c.f5.c12), | 
|         |     83          Face(c.f6.c21, c.f6.c11, c.f3.c21, c.f3.c22), | 
|         |     84          Face(c.f4.c11, c.f4.c12, c.f4.c21, c.f4.c22), | 
|         |     85          Face(c.f5.c11, c.f3.c11, c.f5.c21, c.f3.c12), | 
|         |     86          Face(c.f2.c21, c.f6.c12, c.f2.c22, c.f6.c22)) | 
|         |     87  | 
|         |     88 def right(c: Cube) : Cube = | 
|         |     89     Cube(Face(c.f5.c11, c.f5.c12, c.f1.c21, c.f1.c22), | 
|         |     90          Face(c.f2.c12, c.f2.c22, c.f2.c11, c.f2.c21), | 
|         |     91          Face(c.f3.c11, c.f3.c12, c.f3.c21, c.f3.c22), | 
|         |     92          Face(c.f4.c11, c.f4.c12, c.f6.c12, c.f6.c11), | 
|         |     93          Face(c.f4.c22, c.f4.c21, c.f5.c21, c.f5.c22), | 
|         |     94          Face(c.f1.c11, c.f1.c12, c.f6.c21, c.f6.c22))          | 
|         |     95  | 
|         |     96  | 
|         |     97 // simple bf-search without generating a solution, just true | 
|         |     98  | 
|         |     99 def actions(c: Cube) : List[Cube] =  | 
|         |    100   List(up(c), clock(c), right(c))  | 
|         |    101  | 
|         |    102 def search(cs: List[Cube], d: Int) : Boolean = {  | 
|         |    103   println(s"Depth: $d    Cands: ${cs.length}")   | 
|         |    104   //memory() | 
|         |    105   if (cs.exists(solved == _)) true | 
|         |    106   else search(cs.flatMap(actions), d + 1) | 
|         |    107 }   | 
|         |    108  | 
|         |    109 search(List(init), 0) | 
|         |    110  | 
|         |    111  | 
|         |    112 // set version | 
|         |    113 def actions_set(c: Cube) : Set[Cube] = | 
|         |    114   Set(up(c), clock(c), right(c)) | 
|         |    115  | 
|         |    116 def search_set(cs: Set[Cube], d: Int) : Boolean = { | 
|         |    117   println(s"Depth: $d candidates: ${cs.size}") | 
|         |    118   //memory() | 
|         |    119   if (cs.contains(solved)) true | 
|         |    120   else search_set(cs.flatMap(actions_set), d + 1) | 
|         |    121 }   | 
|         |    122  | 
|         |    123 search_set(Set(init), 0) | 
|         |    124  | 
|         |    125  | 
|         |    126 // for generating list of actions | 
|         |    127 abstract class Action | 
|         |    128 case object Up extends Action | 
|         |    129 case object Right extends Action | 
|         |    130 case object Clock extends Action | 
|         |    131  | 
|         |    132 type Actions = List[Action] | 
|         |    133  | 
|         |    134 // list version generating a list of actions | 
|         |    135 def actions_list(c: Cube, act: Actions) : List[(Cube, Actions)] =  | 
|         |    136   List((up(c), Up::act),  | 
|         |    137        (clock(c), Clock::act),  | 
|         |    138        (right(c), Right::act))  | 
|         |    139  | 
|         |    140  | 
|         |    141 def search_list(cs: List[(Cube, Actions)], d: Int) : (Cube, Actions) = {  | 
|         |    142   println(s"Depth: $d    Cands: ${cs.length}")   | 
|         |    143   val res = cs.find(_._1 == solved) | 
|         |    144   if (res.isDefined) res.get | 
|         |    145   else search_list(cs.flatMap{case (c, as) => actions_list(c, as) }, d + 1) | 
|         |    146 }   | 
|         |    147  | 
|         |    148 search_list(List((init, Nil)), 0)._2.reverse.mkString("\n")  | 
|         |    149  | 
|         |    150  | 
|         |    151 // map version generating a list of actions | 
|         |    152 def actions_map(c: Cube, as: Actions) : Map[Cube, Actions] =  | 
|         |    153   Map(up(c) -> (Up::as),  | 
|         |    154       clock(c) -> (Clock::as),  | 
|         |    155       right(c) -> (Right::as))  | 
|         |    156  | 
|         |    157  | 
|         |    158 def search_map(cs: Map[Cube, Actions], d: Int) : Actions = {  | 
|         |    159   println(s"Depth: $d    Cands: ${cs.keySet.size}")   | 
|         |    160   val res = cs.keySet.find(_ == solved) | 
|         |    161   if (res.isDefined) cs(res.get) | 
|         |    162   else search_map(cs.flatMap{case (c, as) => actions_list(c, as) }, d + 1) | 
|         |    163 }   | 
|         |    164  | 
|         |    165  | 
|         |    166 search_map(Map(init -> Nil), 0).reverse.mkString("\n") | 
|         |    167  | 
|         |    168  | 
|         |    169  | 
|         |    170 // bidirectional breadth-first search | 
|         |    171 def bsearch(cs: Map[Cube, Actions],  | 
|         |    172             bs: Map[Cube, Actions], d: Int) : Actions = {  | 
|         |    173   println(s"Depth: $d    Cands: ${cs.keySet.size}/${bs.keySet.size}")  | 
|         |    174   val res = cs.keySet intersect bs.keySet  | 
|         |    175   if (!res.isEmpty) (cs(res.head).reverse ::: bs(res.head)) | 
|         |    176   else bsearch(cs.flatMap{case (c, as) => actions_map(c, as) },  | 
|         |    177                bs.flatMap{case (c, as) => actions_map(c, as) }, d + 1) | 
|         |    178 }   | 
|         |    179  | 
|         |    180 bsearch(Map(init ->  Nil), Map(solved -> Nil), 0).mkString("\n") | 
|         |    181  | 
|         |    182  | 
|         |    183  | 
|         |    184 // bidirectional breadth-first search | 
|         |    185 def bsearch(cs: Map[Cube, Actions],  | 
|         |    186             bs: Map[Cube, Actions], d: Int) : Actions = {  | 
|         |    187   println(s"Depth: $d    Cands: ${cs.keySet.size}/${bs.keySet.size}")  | 
|         |    188   val res = cs.keySet intersect bs.keySet  | 
|         |    189   if (!res.isEmpty) (cs(res.head).reverse ::: bs(res.head)) | 
|         |    190   else bsearch(cs.flatMap{ (c, as) => actions_map(c, as) },  | 
|         |    191                bs.flatMap{ (c, as) => actions_map(c, as) }, d + 1) | 
|         |    192 }   | 
|         |    193  | 
|         |    194 bsearch(Map(init ->  Nil), Map(solved -> Nil), 0).mkString("\n") | 
|         |    195  | 
|         |    196  | 
|         |    197  | 
|         |    198  | 
|         |    199  | 
|         |    200  | 
|         |    201  | 
|         |    202  | 
|         |    203  | 
|         |    204  | 
|         |    205  | 
|         |    206  | 
|         |    207  | 
|         |    208  | 
|         |    209  | 
|         |    210  | 
|         |    211  | 
|         |    212  | 
|         |    213  | 
|         |    214  |