Advertisement
M1ngXU

23

Dec 23rd, 2021
283
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Rust 6.60 KB | None | 0 0
  1. use std::collections::{ BinaryHeap, HashSet };
  2. use std::{ fmt, cmp, cmp::Ordering };
  3.  
  4. #[derive(Copy, Clone, Debug, Eq, PartialEq)]
  5. enum Location {
  6.     None,
  7.     Amber,
  8.     Bronze,
  9.     Copper,
  10.     Desert
  11. }
  12.  
  13. impl Location {
  14.     fn get_symbol(&self) -> String {
  15.         (match self {
  16.             Location::Amber => "A",
  17.             Location::Bronze => "B",
  18.             Location::Copper => "C",
  19.             Location::Desert => "D",
  20.             Location::None => "."
  21.         }).to_string()
  22.     }
  23.  
  24.     fn get_energy(&self) -> usize {
  25.         match self {
  26.             Location::Amber => 1,
  27.             Location::Bronze => 10,
  28.             Location::Copper => 100,
  29.             Location::Desert => 1000,
  30.             Location::None => 0
  31.         }
  32.     }
  33.  
  34.     fn get_side_door_index(&self) -> usize {
  35.         match self {
  36.             Location::Amber => 0,
  37.             Location::Bronze => 1,
  38.             Location::Copper => 2,
  39.             Location::Desert => 3,
  40.             Location::None => panic!("Tried to get invalid room_side_index.")
  41.         }
  42.     }
  43.    
  44.     fn by_index(i: usize) -> Self {
  45.         match i {
  46.             0 => Location::Amber,
  47.             1 => Location::Bronze,
  48.             2 => Location::Copper,
  49.             3 => Location::Desert,
  50.             _ => panic!("Tried to get invalid location (index: {}).", i)
  51.         }
  52.     }
  53. }
  54.  
  55. #[derive(Copy, Clone)]
  56. struct Situation {
  57.     hallway: [ Location; 11 ],
  58.     side_rooms: [ [ Location; 4 ]; 4 ],
  59.     energy: usize
  60. }
  61.  
  62. impl fmt::Display for Situation {
  63.     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  64.         write!(f, "{}", self.to_string())
  65.     }
  66. }
  67. impl Ord for Situation {
  68.    fn cmp(&self, other: &Self) -> Ordering {
  69.      other.energy.cmp(&self.energy)
  70.    }
  71. }
  72. impl PartialOrd for Situation {
  73.  fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
  74.    Some(other.energy.cmp(&self.energy))
  75.  }
  76. }
  77. impl PartialEq for Situation {
  78.  fn eq(&self, other: &Self) -> bool {
  79.    self.energy == other.energy
  80.  }
  81. }
  82. impl Eq for Situation {}
  83.  
  84. impl Situation {
  85.     fn new(side_rooms: [ [ Location; 4 ]; 4 ]) -> Self {
  86.         Situation {
  87.             hallway: [
  88.                 Location::None,
  89.                 Location::None,
  90.                 Location::None,
  91.                 Location::None,
  92.                 Location::None,
  93.                 Location::None,
  94.                 Location::None,
  95.                 Location::None,
  96.                 Location::None,
  97.                 Location::None,
  98.                 Location::None
  99.             ],
  100.             side_rooms,
  101.             energy: 0
  102.         }
  103.     }
  104.  
  105.     fn finished(&self) -> bool {
  106.         !self.side_rooms.iter().enumerate().any(| (i, s) | s.iter().any(| l | *l != Location::by_index(i)))
  107.     }
  108.  
  109.     fn to_string(&self) -> String {
  110.         format!("=============\nEnergy: {}\n#############\n#{}#\n###{}#{}#{}#{}###\n  #{}#{}#{}#{}#  \n  #{}#{}#{}#{}#  \n  #{}#{}#{}#{}#  \n  #########  ",
  111.             self.energy,
  112.             self.hallway.map(| l | l.get_symbol()).join(""),
  113.             self.side_rooms[0][0].get_symbol(),
  114.             self.side_rooms[1][0].get_symbol(),
  115.             self.side_rooms[2][0].get_symbol(),
  116.             self.side_rooms[3][0].get_symbol(),
  117.             self.side_rooms[0][1].get_symbol(),
  118.             self.side_rooms[1][1].get_symbol(),
  119.             self.side_rooms[2][1].get_symbol(),
  120.             self.side_rooms[3][1].get_symbol(),
  121.             self.side_rooms[0][2].get_symbol(),
  122.             self.side_rooms[1][2].get_symbol(),
  123.             self.side_rooms[2][2].get_symbol(),
  124.             self.side_rooms[3][2].get_symbol(),
  125.             self.side_rooms[0][3].get_symbol(),
  126.             self.side_rooms[1][3].get_symbol(),
  127.             self.side_rooms[2][3].get_symbol(),
  128.             self.side_rooms[3][3].get_symbol()
  129.         )
  130.     }
  131. }
  132.  
  133. fn main() {
  134.     let s = Situation::new([
  135.         /*
  136.         [
  137.             Location::Desert,
  138.             Location::Desert,
  139.             Location::Desert,
  140.             Location::Bronze
  141.         ], [
  142.             Location::Bronze,
  143.             Location::Copper,
  144.             Location::Bronze,
  145.             Location::Desert
  146.         ], [
  147.             Location::Amber,
  148.             Location::Bronze,
  149.             Location::Amber,
  150.             Location::Amber
  151.         ], [
  152.             Location::Copper,
  153.             Location::Amber,
  154.             Location::Copper,
  155.             Location::Copper
  156.         ]*/
  157.         // for part one the last 2 amphipod have to be AA/BB/CC/DD (they won't be moved)
  158.         [
  159.             Location::Desert,
  160.             Location::Bronze,
  161.             Location::Amber,
  162.             Location::Amber
  163.         ], [
  164.             Location::Bronze,
  165.             Location::Desert,
  166.             Location::Bronze,
  167.             Location::Bronze
  168.         ], [
  169.             Location::Amber,
  170.             Location::Amber,
  171.             Location::Copper,
  172.             Location::Copper
  173.         ], [
  174.             Location::Copper,
  175.             Location::Copper,
  176.             Location::Desert,
  177.             Location::Desert
  178.         ]
  179.     ]);
  180.     let possible_end_pos = [ 0, 1, 3, 5, 7, 9, 10 ];
  181.     let mut visited = HashSet::new();
  182.     visited.insert(s.to_string());
  183.     let mut stack = BinaryHeap::new();
  184.     stack.push(s);
  185.     let mut seen = 0;
  186.     while let Some(current) = stack.pop() {
  187.         if seen % 1000 == 0 {
  188.             println!("Current energy: {}; Seen {}; Stack has now a size of {}", current.energy, seen, stack.len());
  189.         }
  190.         seen += 1;
  191.         if current.finished() {
  192.             println!("{}", current);
  193.             break;
  194.         }
  195.  
  196.         let hallway_empty = | mut from: usize, mut to: usize, o | {
  197.             if from > to {
  198.                 let t = to;
  199.                 to = from - o;
  200.                 from = t;
  201.             } else {
  202.                 from += o;
  203.             }
  204.             !(from..=to).into_iter().any(| i | current.hallway[i] != Location::None)
  205.         };
  206.  
  207.         let mut moved_into_side = false;
  208.  
  209.         for (i, a) in current.hallway.iter().enumerate().filter(| (_, a) | *(*a) != Location::None) {
  210.             let side_door_index = a.get_side_door_index();
  211.             if hallway_empty(i, side_door_index * 2 + 2, 1) && !current.side_rooms[side_door_index].iter().any(| l | *l != Location::by_index(side_door_index) && *l != Location::None) {
  212.                 if let Some(r_i) = current.side_rooms[side_door_index].iter().rposition(| l | *l == Location::None) {
  213.                     let to_be_moved = current.hallway[i];
  214.                     let mut new_situation = current.clone();
  215.                     new_situation.side_rooms[side_door_index][r_i] = to_be_moved;
  216.                     new_situation.hallway[i] = Location::None;
  217.                     new_situation.energy += to_be_moved.get_energy() * (cmp::max(i, side_door_index * 2 + 2) - cmp::min(i, side_door_index * 2 + 2) + r_i + 1);
  218.                     if !visited.contains(&new_situation.to_string()) {
  219.                         visited.insert(new_situation.to_string());
  220.                         stack.push(new_situation);
  221.                     }
  222.                     moved_into_side = true;
  223.                 }
  224.             }
  225.         }
  226.  
  227.         if moved_into_side {
  228.             continue;
  229.         }
  230.  
  231.         for (sr_i, sr) in current.side_rooms
  232.                 .iter().enumerate()
  233.                 .filter(| (i, sr) | sr.iter().any(| l | *l != Location::by_index(*i) && *l != Location::None)) {
  234.             if let Some(r_i) = sr.iter().position(| a | *a != Location::None) {
  235.                 let hallway_index = sr_i * 2 + 2;
  236.                 for i in possible_end_pos {
  237.                     if hallway_empty(i, hallway_index, 0) {
  238.                         let to_be_moved = sr[r_i];
  239.                         let mut new_situation = current.clone();
  240.                         new_situation.side_rooms[sr_i][r_i] = Location::None;
  241.                         new_situation.hallway[i] = to_be_moved;
  242.                         new_situation.energy += to_be_moved.get_energy() * (cmp::max(i, hallway_index) - cmp::min(i, hallway_index) + r_i + 1);
  243.                         if !visited.contains(&new_situation.to_string()) {
  244.                             visited.insert(new_situation.to_string());
  245.                             stack.push(new_situation);
  246.                         }
  247.                     }
  248.                 }
  249.             }
  250.         }
  251.     }
  252. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement