Solitaire.java [src/java/m/example/solitaire] Revision:   Date:
package m.example.solitaire;

import csip.utils.CheckPointing;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

/**
 *
 * @author od
 */
public class Solitaire {

  static final int FROM = 0;
  static final int OVER = 1;
  static final int TO = 2;

  static final int[][] JUMPS = {
    {0, 2, 5},
    {0, 1, 3},
    {1, 4, 8},
    {1, 3, 6},
    {2, 5, 9},
    {2, 4, 7},
    {3, 1, 0},
    {3, 4, 5},
    {3, 7, 12},
    {3, 6, 10},
    {4, 8, 13},
    {4, 7, 11},
    {5, 9, 14},
    {5, 8, 12},
    {5, 4, 3},
    {5, 2, 0},
    {6, 3, 1},
    {6, 7, 8},
    {7, 4, 2},
    {7, 8, 9},
    {8, 7, 6},
    {8, 4, 1},
    {9, 8, 7},
    {9, 5, 2},
    {10, 6, 3},
    {10, 11, 12},
    {11, 7, 4},
    {11, 12, 13},
    {12, 8, 5},
    {12, 13, 14},
    {12, 11, 10},
    {12, 7, 3},
    {13, 12, 11},
    {13, 8, 4},
    {14, 13, 12},
    {14, 9, 5}
  };

  int numBoards = 0;
  int[] solutions = new int[15];
  boolean[] initialBoard = {
    true,
    true, true,
    true, true, true,
    true, true, true, true,
    true, true, true, true, true
  };

  int missing;


  public Solitaire(int missing) {
    initialBoard[missing] = false;
    this.missing = missing;
  }

  static class Board {

    boolean[] board;
    int from;
    int to;
    Board prev;


    Board(boolean[] board, int from, int to, Board prev) {
      this.board = board;
      this.from = from;
      this.to = to;
      this.prev = prev;
    }


    Board jump(int from, int over, int to) {
      if (board[from] && board[over] && !board[to]) {
        boolean b[] = (boolean[]) board.clone();
        b[from] = b[over] = false;
        b[to] = true;
        return new Board(b, from, to, this);
      }
      return null;
    }


    List<Board> allJumps() {
      List<Board> bs = new LinkedList<>();
      Board b;
      for (int[] j : JUMPS) {
        if ((b = jump(j[FROM], j[OVER], j[TO])) != null)
          bs.add(b);
      }
      return bs;
    }


    int getCount() {
      int count = 0;
      for (boolean pin : board) {
        if (pin)
          count++;
      }
      return count;
    }


    @Override
    public String toString() {
      return new StringBuffer().append(from)
          .append('\u2192').append(to).toString();
    }
  }


  void solve(Board b) {
    List<Board> boards = b.allJumps();
    if (boards.isEmpty()) {

      // no more moves
      // if (b.getCount() == 1)
      //   System.out.println(allMoves(b));
      solutions[b.getCount()]++;
      return;
    }

    numBoards += boards.size();

    for (Board b1 : boards) {
      solve(b1);
    }
  }


  void solveAll() {
    solve(new Board(initialBoard, 0, 0, null));
  }


  StringBuffer allMoves(Board b) {
    if (b.prev == null)
      return new StringBuffer();
    return allMoves(b.prev).append(b).append(", ");
  }


  public void stats() {
    System.out.println("Start pos: " + missing);
    System.out.println("# of Solutions per remaining pins (0..14): " + Arrays.toString(solutions));
    System.out.println("total # Solutions: " + Arrays.stream(solutions).sum());
    System.out.println("# of 'One remaining pin' Solutions: " + solutions[1]);
    System.out.println("% of 'One remaining pin' per total: " + (double) solutions[1]
        / Arrays.stream(solutions).sum());
    System.out.println("# Boards: " + numBoards);
    System.out.println();
  }


  // layout
  // 
  //       x
  //      x x
  //     x _ x
  //    x x x x
  //   x x x x x
  //
  // Board position ids (for moves):
  // 
  //        0
  //       1  2
  //     3  4  5
  //   6  7  8  9 
  // 10 11 12 13 14
  //
  public static void main(String[] args) {
    CheckPointing cp = new CheckPointing();
    cp.check("start");
    for (int missing = 0; missing < 15; missing++) {
      Solitaire s = new Solitaire(missing);
      s.solveAll();
      s.stats();
    }
    cp.check("done");
    System.out.println(cp);
  }

}