progs/cube2.scala
changeset 463 0315d9983cd0
parent 417 29fc780ca130
equal deleted inserted replaced
462:34feeb53c0ba 463:0315d9983cd0
       
     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