rubikscube

college code for finding optimal rubiks cube solutions in java

git clone https://9o.is/git/rubikscube.git

RubiksPatternTable.java

(7961B)


      1 import java.util.ArrayList;
      2 import java.util.LinkedList;
      3 import java.util.List;
      4 import java.util.Queue;
      5 
      6 /**
      7  * Generates tables of ALL attainable Rubik's cube states alongside
      8  * heuristics or the amount of moves to its goal state.
      9  */
     10 public class RubiksPatternTable {
     11 
     12     /*
     13      * All attainable corner states of a rubik's cube.
     14      * There are 8! * 3^7 = 88,179,840 possible combination.
     15      */
     16     private byte[] corners =
     17             new byte[88179840];
     18 
     19     /*
     20      * Half of all attainable edge states of a  rubik's cube.
     21      * There are 12!/6! * 2^6 = 42,577,920 possible combinations.
     22      */
     23     private byte[] halfEdges =
     24             new byte[42577920];
     25 
     26     /*
     27     * Second half of all attainable edge states of a  rubik's cube.
     28     * There are 12!/6! * 2^6 = 42,577,920 possible combinations.
     29     */
     30     private byte[] half2Edges =
     31             new byte[42577920];
     32 
     33     /*
     34      * All attainable corner states of a rubik's cube,
     35      * alongside its heuristic, will be stored in a table (file).
     36      */
     37     private PatternTable cornersTable;
     38 
     39     /*
     40      * Half of all attainable edge states of a rubik's cube,
     41      * alongside its heuristic, will be stored in a table (file).
     42      */
     43     private PatternTable halfEdgesTable;
     44 
     45     /*
     46      * Second half of all attainable edge states of a rubik's cube,
     47      * alongside its heuristic, will be stored in a table (file).
     48      */
     49     private PatternTable half2EdgesTable;
     50 
     51     /**
     52      * Create a Rubik's Pattern Table.
     53      */
     54     public RubiksPatternTable() {
     55         cornersTable = new PatternTable("corners.txt");
     56         halfEdgesTable = new PatternTable("halfEdges.txt");
     57         half2EdgesTable = new PatternTable("half2Edges.txt");
     58         transferCorners(cornersTable.readTable());
     59         transferHalfEdge(halfEdgesTable.readTable());
     60         transferHalf2Edge(half2EdgesTable.readTable());
     61     }
     62 
     63     /**
     64      * Create a Rubik's Pattern Table with specified files.
     65      * @param corners File to store corner states.
     66      * @param halfEdges File to store half of the edge states.
     67      * @param half2Edges File to store other half of the edge states.
     68      */
     69     RubiksPatternTable(PatternTable corners,
     70                        PatternTable halfEdges,
     71                        PatternTable half2Edges) {
     72         this.cornersTable = corners;
     73         this.halfEdgesTable = halfEdges;
     74         this.half2EdgesTable = half2Edges;
     75         transferCorners(cornersTable.readTable());
     76         transferHalfEdge(halfEdgesTable.readTable());
     77         transferHalf2Edge(half2EdgesTable.readTable());
     78     }
     79 
     80     /**
     81      * Generates a pattern table of all possible rubik's cube states.
     82      * Tables are separated by corners and half of the edges.
     83      * @throws Exception
     84      */
     85     public void generateTables() throws Exception {
     86         // start at the goal state and add it to queue
     87         RubiksState rootCube =
     88                 new RubiksState(RubiksCube.GOAL,1);
     89 
     90         Queue<RubiksState> travq = new LinkedList<RubiksState>();
     91         travq.add(rootCube);
     92 
     93         // traverse the queue and handle appropriately
     94         RubiksState current;
     95         while(!travq.isEmpty()) {
     96             try {
     97                 // poll the queue and convert it to state and cube
     98                 // for easier manipulation
     99                 current = travq.poll();
    100                 RubiksCube cube = new RubiksCube(current);
    101 
    102                 // iterate the current cube's neighbors; add to queue
    103                 // if the state hasn't been added yet
    104                 for(RubiksState neighbor : cube.getNeighborStates()) {
    105                     if(corners[neighbor.getCorners().hashState()]==0 &&
    106                        halfEdges[neighbor.getHalfEdges().hashState()]==0 &&
    107                        half2Edges[neighbor.getHalf2Edges().hashState()]==0)
    108                         travq.add(new RubiksState(
    109                                 neighbor,
    110                                 current.getHeuristic()+1));
    111                 }
    112 
    113                 // save corner state to array and table
    114                 RubiksSubState cornerstate =
    115                         new RubiksCornerState(
    116                                 current.getCorners().toString(),
    117                                 current.getHeuristic());
    118                 int hash = cornerstate.hashState();
    119                 if(corners[hash] == 0) {
    120                     corners[hash] = cornerstate.getHeuristic();
    121                     cornersTable.updateTable(hash, cornerstate.getHeuristic());
    122                 }
    123 
    124                 // save first set of edges to array and table
    125                 RubiksSubState halfedgestate =
    126                         new RubiksHalfEdgeState(
    127                                 current.getHalfEdges().toString(),
    128                                 current.getHeuristic());
    129                 hash = halfedgestate.hashState();
    130                 if(halfEdges[hash] == 0) {
    131                     halfEdges[hash] = halfedgestate.getHeuristic();
    132                     halfEdgesTable.updateTable(hash, halfedgestate.getHeuristic());
    133                 }
    134 
    135                 // save second set of edges to array and table
    136                 RubiksSubState half2edgestate =
    137                         new RubiksHalfEdgeState(
    138                                 current.getHalf2Edges().toString(),
    139                                 current.getHeuristic());
    140                 hash = half2edgestate.hashState();
    141                 if(half2Edges[hash] == 0) {
    142                     half2Edges[hash] = half2edgestate.getHeuristic();
    143                     half2EdgesTable.updateTable(hash, half2edgestate.getHeuristic());
    144                 }
    145 
    146                 /*System.out.println(
    147                         "Added State: "+current.getState() +
    148                                 " -> Heuristic: "+current.getHeuristic());*/
    149 
    150            } catch (Exception e) {
    151                 e.printStackTrace();
    152             }
    153         }
    154     }
    155 
    156     /* Checks if current rubik's state is unique among a group of cubes. */
    157     private boolean isCubeUnique(List<RubiksCube> cubes, RubiksState current) {
    158         for(RubiksCube check : cubes) {
    159             if(check.isEqualTo(new RubiksCube(current)))
    160                 return false;
    161         }
    162         return true;
    163     }
    164 
    165     /* Transfers table state to array. */
    166     private void transferCorners(byte[] values) {
    167         for(int i=0; i<corners.length; i++) {
    168             corners[i] = values[i];
    169         }
    170     }
    171 
    172     /* Transfers table state to array. */
    173     private void transferHalfEdge(byte[] values) {
    174         for(int i=0; i<halfEdges.length; i++) {
    175             halfEdges[i] = values[i];
    176         }
    177     }
    178 
    179     /* Transfers table state to array. */
    180     private void transferHalf2Edge(byte[] values) {
    181         for(int i=0; i<half2Edges.length; i++) {
    182             half2Edges[i] = values[i];
    183         }
    184     }
    185 
    186     /**
    187      * Retrieve pattern table of all corner states.
    188      * @return  Pattern table of all corner states.
    189      */
    190     public PatternTable getCornersTable() {
    191         return cornersTable;
    192     }
    193 
    194     /**
    195      * Retrieve pattern table for the first half of all edge states.
    196      * @return  Pattern table for the first half of all edge states.
    197      */
    198     public PatternTable getHalfEdgesTable() {
    199         return halfEdgesTable;
    200     }
    201 
    202     /**
    203      * Retrieve pattern table for the second half of all edge states.
    204      * @return  Pattern table for the second half of all edge states.
    205      */
    206     public PatternTable getHalf2EdgesTable() {
    207         return half2EdgesTable;
    208     }
    209 
    210     /**
    211      * Retrieve all corner states.
    212      * @return all corner states.
    213      */
    214     public byte[] getCorners() {
    215         return corners;
    216     }
    217 
    218     /**
    219      * Retrieve first half of all edge states.
    220      * @return first half of all edge states.
    221      */
    222     public byte[] getHalfEdges() {
    223         return halfEdges;
    224     }
    225 
    226     /**
    227      * Retrieve second half of all edge states.
    228      * @return second half of all edge states.
    229      */
    230     public byte[] getHalf2Edges() {
    231         return half2Edges;
    232     }
    233 }