Beispiel #1
0
 // Copy constructor. Sharing amphipod references doesn't matter.
 public c_burrow(c_burrow other) : this(other.home_depth)
 {
     for (int column = 0; column < burrow_positions.Length; column++)
     {
         for (int row = 0; row < burrow_positions[column].Length; row++)
         {
             burrow_positions[column][row] = other.burrow_positions[column][row];
         }
     }
 }
Beispiel #2
0
            // Try to solve the burrow
            public (bool, int) try_solve(bool pretty, List <c_burrow> solution_stack, string depth_string = "")
            {
                solution_stack.Add(new c_burrow(this));

                if (pretty)
                {
                    display("try_solve", depth_string);
                }

                int cost = 0;

                // First try to move any amphipods to their solved positions. This is always the best thing to do.
                int clear_cost = int.MaxValue;

                while (clear_cost > 0)
                {
                    clear_cost = 0;

                    clear_cost += try_clear_hallway();
                    clear_cost += try_clear_homes();

                    cost += clear_cost;
                }

                // if some amphipods were moved to their homes, note that in the solution stack.
                if (cost > 0)
                {
                    solution_stack.Add(new c_burrow(this));

                    if (pretty)
                    {
                        display(string.Format("moved some home (cost = {0})", cost), depth_string);
                    }
                }

                // If the burrow is solved, return.
                if (is_solved())
                {
                    if (pretty)
                    {
                        Console.WriteLine(depth_string + "solved!");
                    }

                    return(true, cost);
                }

                // I don't know what to do now but we have to move somebody out of a burrow.
                // So try using brute force on every possible move and use the best result we find.
                // ... turns out this still solves things in about a second. Yay!

                List <c_burrow> best_guess_stack  = null;
                bool            best_guess_solved = false;
                int             best_guess_cost   = int.MaxValue;

                // Loop through each home we could pull an amphipod out of
                foreach (int start_column in k_home_columns)
                {
                    (c_amphipod start, int start_row) = find_top_in_unfinished_home(start_column);

                    // If the top amphipod in this home was found
                    if (start != null)
                    {
                        (int min_end_column, int max_end_column) = get_valid_parking_spots(start_column);

                        // Loop through each place we could move it to
                        foreach (int end_column in k_hallway_parking_spot_columns)
                        {
                            if (end_column >= min_end_column && end_column <= max_end_column)
                            {
                                c_amphipod end = this.burrow_positions[end_column][0];

                                // If we find an empty spot to move it to
                                if (end == null)
                                {
                                    // Move the amphipod to that spot in the hallway and recurse.

                                    c_burrow guess = new c_burrow(this);

                                    guess.burrow_positions[end_column][0]           = start;
                                    guess.burrow_positions[start_column][start_row] = null;

                                    List <c_burrow> guess_stack = new List <c_burrow>();

                                    (bool guess_solved, int guess_cost) = guess.try_solve(pretty, guess_stack, depth_string + "\t");

                                    // If this branch of recursion solved the burrow and it's the best cost we've found so far, save the results.
                                    if (guess_solved)
                                    {
                                        int initial_guess_cost = (start_row + Math.Abs(end_column - start_column)) * start.cost_per_move;

                                        guess_cost += initial_guess_cost;

                                        if (guess_cost < best_guess_cost)
                                        {
                                            best_guess_solved = true;
                                            best_guess_cost   = guess_cost;
                                            best_guess_stack  = guess_stack;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }

                // Some branch of recursion found a solution.
                if (best_guess_solved)
                {
                    if (pretty)
                    {
                        Console.WriteLine(depth_string + "a guess solved");
                    }

                    solution_stack.AddRange(best_guess_stack);

                    return(best_guess_solved, cost + best_guess_cost);
                }
                // No solution was found.
                else
                {
                    if (pretty)
                    {
                        Console.WriteLine(depth_string + "no guesses solved");
                    }

                    return(false, 0);
                }
            }