public static void FujisanMain() { int TRIALS = 1; int EXP = 100; // Choose here the setup algorithm you wish to use FujisanSetup setup = FujisanSetup.PIECEPACK; // Choose here the search algorithm for the solver Search search = Search.ASTAR; List <int> hist = new List <int>(); List <int> countermoves = new List <int>(); Random random = new Random(); // Easy output for copying into a spreadsheet Console.WriteLine("solved\tdead\tavelen\tsconn\tfconn"); // Run the specified number of experiments within the number // of specified trials for (int t = 0; t < TRIALS; t++) { int count = 0; int lensum = 0; int dead = 0; double sconn = 0; double fconn = 0; int max = 0; Parallel.For(0, EXP, i => //for (int i = 0; i < EXP; i++) { // Total count of boards, for HashSet later int bcount = 0; // Store all boards seen in found HashSet <Board> found = new HashSet <Board>(); // Keep track of board states to explore in frontier // Sort them by heuristic plus current path length for A* SortedList <double, Board> frontier = new SortedList <double, Board>(); // Create a new board and place it in the frontier Board start = new Board(random, setup); Console.WriteLine(start); Console.WriteLine("Starting:"); Console.WriteLine(start + "\n"); frontier.Add(start.length + start.Heuristic() + (1e-12 * bcount), start); // Keep searching the frontier until it is empty or // a solution is found bool solved = false; while (frontier.Count > 0) { // Take the most promising board state, remove from // frontier and add it to the found set var keys = frontier.Keys; var first = keys[0]; Board board = frontier[first]; frontier.Remove(first); found.Add(board); // Find the children of the current board List <Board> children = board.GetChildren(); List <Board> stuff = new List <Board>(); if (search == Search.ASTAR) { stuff = children; } else // Pick a child randomly { if (children.Count > 0) { stuff.Add(children[random.Next(0, children.Count)]); } } Console.WriteLine(frontier.Count); foreach (Board b in stuff) { // Did you find a solution? if (b.Solved()) { // Yay! Record statistics solved = true; Debug.WriteLine("SOLUTION!!!!"); Debug.WriteLine(b.Path()); frontier.Clear(); lock (random) { sconn += start.ConnectionStrength(); lensum += b.length; count++; Console.WriteLine(b.length + "," + b.countermoves + "," + b.MovePath()); if (b.length > max) { Debug.WriteLine("SOLUTION!!!!"); Debug.WriteLine(b.Path()); max = b.length; } } break; } // If you have never seen this board before // Add it to the frontier if (!found.Contains(b) && !frontier.ContainsValue(b)) { bcount++; frontier.Add(b.length + b.Heuristic() + (1e-12 * bcount), b); } else { //Console.WriteLine("WOAH!"); } } } // Record when no children of initial state could be found if (!solved) { fconn += start.ConnectionStrength(); if (found.Count == 1) { lock (random) { dead++; } } } }); Console.WriteLine(((float)count / EXP) + "\t" + ((float)dead / EXP) + "\t" + ((float)lensum / count) + "\t" + sconn / count + "\t" + fconn / (EXP - count)); } Console.WriteLine("Steps"); foreach (int i in hist) { Console.WriteLine(i); } Console.WriteLine("CounterMoves"); foreach (int i in countermoves) { Console.WriteLine(i); } }
/****** * Creates a random starting board state */ public Board(Random random, FujisanSetup s) { this.random = random; move = "START"; moveType = FujisanMoveType.START; values = new int[2, 14]; if (s == FujisanSetup.ENGRAVED) { // Make the 20 tiles matching domino distribution List <Tile> list = new List <Tile>(); for (int i = 0; i < 6; i++) { int start = i; if (i == 0) { start = 1; } for (int j = start; j < 6; j++) { list.Add(new Tile(i, j)); } } //Console.WriteLine("AUGH!!!!" + list.Count); Shuffle <Tile>(list, random); // Fill in numbers on the left half int t = -1; for (int i = 0; i < 5; i++) { t++; if (random.NextDouble() > 0.5) { list[t].Rotate(); } values[0, t + 1] = list[t].values[0, 0]; values[1, t + 1] = list[t].values[1, 0]; } values[0, t + 2] = list[t].values[0, 1]; values[1, t + 2] = list[t].values[1, 1]; // Fill in numbers on the right half for (int i = 0; i < 5; i++) { t++; if (random.NextDouble() > 0.5) { list[t].Rotate(); } values[0, 12 - i] = list[t].values[0, 1]; values[1, 12 - i] = list[t].values[1, 1]; } values[0, 7] = list[t].values[0, 0]; values[1, 7] = list[t].values[1, 0]; } else if (s == FujisanSetup.DOMINO) { // Make the 15 tiles matching domino distribution List <Tile> list = new List <Tile>(); for (int i = 0; i < 6; i++) { int start = i + 1; for (int j = start; j < 6; j++) { list.Add(new Tile(i, j)); } } //Console.WriteLine("AUGH!!!!" + list.Count); Shuffle <Tile>(list, random); // Fill in numbers on the left half int t = -1; for (int i = 0; i < 6; i++) { t++; if (random.NextDouble() > 0.5) { list[t].Rotate(); } values[0, t + 1] = list[t].values[0, 0]; values[1, t + 1] = list[t].values[1, 0]; } // Fill in numbers on the right half for (int i = 0; i < 6; i++) { t++; if (random.NextDouble() > 0.5) { list[t].Rotate(); } values[0, 12 - i] = list[t].values[0, 1]; values[1, 12 - i] = list[t].values[1, 1]; } } else if (s == FujisanSetup.PIECEPACK) { // Make the coins for the piecepack List <Byte>[] coins = new List <Byte> [4]; for (int i = 0; i < 4; i++) { coins[i] = new List <Byte>(); } for (int i = 0; i < 6; i++) { for (int j = 0; j < 4; j++) { coins[j].Add((byte)i); } } // Shuffle the coins within each type (sun, moon, etc) for (int i = 0; i < 4; i++) { Shuffle <Byte>(coins[i], random); } // Place the coins on the board, starting at the // right, and filling two from each type at a time int where = 12; for (int k = 0; k < 3; k++) { for (int i = 0; i < 4; i++) { for (int j = 0; j < 2; j++) { values[j, where] = coins[i][j + k * 2]; } where--; } } } else if (s == FujisanSetup.ANYCOIN) { // Make the coins for the piecepack List <Byte> coins = new List <Byte>(); for (int i = 0; i < 6; i++) { for (int j = 0; j < 4; j++) { coins.Add((byte)i); } } // Shuffle the coins Shuffle <Byte>(coins, random); // Place the coins on the board, starting at the // right, and filling two from each type at a time int where = 12; for (int k = 0; k < 12; k++) { for (int j = 0; j < 2; j++) { values[j, where] = coins[j + k * 2]; } where--; } } else if (s == FujisanSetup.HARDCODE) { // Initial board from Puzzle Four // http://www.ludism.org/ppwiki/Fuji-san#Heading9 values[0, 12] = 5; values[1, 12] = 4; values[0, 11] = 3; values[1, 11] = 5; values[0, 10] = 3; values[1, 10] = 0; values[0, 9] = 4; values[1, 9] = 1; values[0, 8] = 2; values[1, 8] = 0; values[0, 7] = 2; values[1, 7] = 0; values[0, 6] = 2; values[1, 6] = 1; values[0, 5] = 0; values[1, 5] = 3; values[0, 4] = 1; values[1, 4] = 3; values[0, 3] = 1; values[1, 3] = 4; values[0, 2] = 5; values[1, 2] = 4; values[0, 1] = 5; values[1, 1] = 2; } else if (s == FujisanSetup.RANDOM) { for (int i = 0; i < 2; i++) { for (int j = 1; j < 13; j++) { values[i, j] = random.Next(0, 6); } } } // Place the pawns on the edges of the board pawns = new int[2, 14]; pawns[0, 0] = 1; pawns[1, 0] = 1; pawns[0, 13] = 1; pawns[1, 13] = 1; }