Ejemplo n.º 1
0
            // Try to send the amphipod in this spot to thier home
            private (bool, int) try_send_to_home(
                int start_column,
                int start_row)
            {
                c_amphipod start = burrow_positions[start_column][start_row];

                // Assume if they start in a home, then nobody is above them.
                bool path_home_clear = true;

                int min_hallway_column = Math.Min(start_column, start.target_column);
                int max_hallway_column = Math.Max(start_column, start.target_column);

                // check if the path along the hallway is clear
                for (int path_column = min_hallway_column;
                     path_column <= max_hallway_column && path_home_clear;
                     path_column++)
                {
                    c_amphipod hallway_position = burrow_positions[path_column][0];
                    if (hallway_position != null && hallway_position != start)
                    {
                        // a spot in the hallway isn't clear
                        path_home_clear = false;
                    }
                }

                int target_row = 0;

                // check to see if the home is clear or filled with friends
                c_amphipod[] home = burrow_positions[start.target_column];

                for (int path_row = 1; path_row < home.Length && path_home_clear; path_row++)
                {
                    c_amphipod home_position = home[path_row];

                    // Every time we find a clear home position, it's the best candidate for the target position.
                    if (home_position == null)
                    {
                        target_row = path_row;
                    }

                    // If we find someone in the home that shouldn't be there, then we can't move to this home right now.
                    if (home_position != null && home_position.type != start.type)
                    {
                        path_home_clear = false;
                    }
                }

                // If the path home was clear, move the amphipod and return the total cost.
                if (path_home_clear)
                {
                    int cost = (start_row + target_row + Math.Abs(start.target_column - start_column)) * start.cost_per_move;

                    burrow_positions[start.target_column][target_row] = start;
                    burrow_positions[start_column][start_row]         = null;

                    return(true, cost);
                }

                return(false, 0);
            }
Ejemplo n.º 2
0
            // Create a burrow with no amphipods in it
            public c_burrow(int h)
            {
                home_depth       = h;
                burrow_positions = new c_amphipod[11][];

                foreach (int column in k_home_columns)
                {
                    burrow_positions[column] = new c_amphipod[home_depth + 1];
                }

                foreach (int column in k_hallway_parking_spot_columns)
                {
                    burrow_positions[column] = new c_amphipod[1];
                }
            }
Ejemplo n.º 3
0
            // return true if the burrow is solved
            private bool is_solved()
            {
                foreach (int column in k_home_columns)
                {
                    c_amphipod[] home = burrow_positions[column];

                    for (int row = 1; row < home.Length; row++)
                    {
                        c_amphipod current = home[row];

                        if (current == null || current.target_column != column)
                        {
                            return(false);
                        }
                    }
                }

                return(true);
            }
Ejemplo n.º 4
0
            // Find the top amphipod in this home, but only if this home isn't solved yet.
            private (c_amphipod, int) find_top_in_unfinished_home(int column)
            {
                c_amphipod[] start_home = burrow_positions[column];

                int        top_row            = 0;
                c_amphipod top                = null;
                bool       home_has_neighbors = false;

                // Find the top amphipod in this home
                for (int row = 1; row < start_home.Length; row++)
                {
                    c_amphipod current = start_home[row];

                    if (current != null)
                    {
                        // Remember the top one we find
                        if (top == null)
                        {
                            top_row = row;
                            top     = current;
                        }

                        // Remember if any aren't supposed to be there
                        if (current.target_column != column)
                        {
                            home_has_neighbors = true;
                        }
                    }
                }

                // Only return success if this home is not solved.
                if (!home_has_neighbors)
                {
                    return(null, 0);
                }
                else
                {
                    return(top, top_row);
                }
            }
Ejemplo n.º 5
0
            // Try to send an amphipod in the hallway to their home
            private (bool, int) try_send_hallway_to_home()
            {
                // Look at each spot in the hallway.
                for (int start_column = 0; start_column < burrow_positions.Length; start_column++)
                {
                    c_amphipod start = burrow_positions[start_column][0];

                    // If we found an amphibod in the hallway, check to see if their path home is clear
                    if (start != null)
                    {
                        // If we can move them home, return that cost.
                        (bool moved, int cost) = try_send_to_home(start_column, 0);

                        if (moved)
                        {
                            return(moved, cost);
                        }
                    }
                }

                return(false, 0);
            }
Ejemplo n.º 6
0
 // Place a single amphipod in the burrow.
 public void place_amphipod(char type, int row, int column)
 {
     burrow_positions[column][row] = new c_amphipod(type);
 }
Ejemplo n.º 7
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);
                }
            }