Guest User

Untitled

a guest
Jul 8th, 2025
307
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Rust 7.44 KB | None | 0 0
  1. use std::cmp::Ordering;
  2. use std::cmp::min;
  3. use std::collections::HashMap;
  4. use std::fmt;
  5.  
  6. type Color = u32;
  7. type Column = Vec<Color>;
  8.  
  9. #[derive(Debug, PartialEq, Eq)]
  10. enum Score {
  11.     Win,
  12.     Score(usize),
  13. }
  14.  
  15. impl Ord for Score {
  16.     fn cmp(&self, other: &Self) -> Ordering {
  17.         match (self, other) {
  18.             (Score::Win, _) => Ordering::Greater,
  19.             (_, Score::Win) => Ordering::Less,
  20.             (Score::Score(s1), Score::Score(s2)) => s1.cmp(s2),
  21.         }
  22.     }
  23. }
  24.  
  25. impl PartialOrd for Score {
  26.     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
  27.         Some(self.cmp(other))
  28.     }
  29. }
  30.  
  31. #[derive(Debug, Clone)]
  32. struct Puzzle {
  33.     column_size: usize,
  34.     colors_count: HashMap<Color, usize>,
  35.     state: Vec<Column>,
  36. }
  37.  
  38. impl fmt::Display for Puzzle {
  39.     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  40.        writeln!(f)?;
  41.        for i in 0..self.column_size {
  42.            if i > 0 {
  43.                writeln!(f)?;
  44.            }
  45.            for j in 0..self.state.len() {
  46.                let col = &self.state[j];
  47.                if j > 0 {
  48.                    write!(f, " ")?;
  49.                }
  50.                let idx = self.column_size - i - 1;
  51.                let c = col
  52.                    .get(idx)
  53.                    // This is pretty bad since it will only print something meaningful if callers
  54.                    // passed values from 0 to 9 in the columns, but this is just toy code anyways.
  55.                    .map(|&x| char::from_digit(x, 10).unwrap_or('?'))
  56.                    .unwrap_or(' ');
  57.                write!(f, "[{c}]")?;
  58.            }
  59.        }
  60.        Ok(())
  61.    }
  62. }
  63.  
  64. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
  65. struct Move(usize, usize);
  66.  
  67. #[derive(Debug)]
  68. struct MoveTree {
  69.    game: Puzzle,
  70.    children: HashMap<Move, MoveTree>,
  71. }
  72.  
  73. impl Puzzle {
  74.    fn new(column_size: usize, init: &[Vec<u32>]) -> Puzzle {
  75.        let mut p = Puzzle {
  76.            column_size,
  77.            colors_count: HashMap::new(),
  78.            state: Vec::new(),
  79.        };
  80.  
  81.        for col in init {
  82.            let mut vec = Vec::with_capacity(column_size);
  83.            for &c in &col[..min(column_size, col.len())] {
  84.                let entry = p.colors_count.entry(c).or_insert(0);
  85.                *entry += 1;
  86.                vec.push(c);
  87.            }
  88.            p.state.push(vec);
  89.        }
  90.        p
  91.    }
  92.  
  93.    fn rank(&self) -> Score {
  94.        let mut score: usize = 0;
  95.        let mut done = true;
  96.  
  97.        for (i, col) in self.state.iter().enumerate() {
  98.            // Adding the number of moves to the score to promote states that are not stuck.
  99.            score += self.column_moves(i).len();
  100.            // We use self.state.len() as a multiplier to ensure the various conditions below
  101.            // (empty columns, columns with just one color, columns fully sorted with all the
  102.            // entries of that color) dominate over just being able to move items.
  103.            if let Some(&c) = col.last() {
  104.                if col.iter().all(|&c2| c2 == c) {
  105.                    // Column containing just a single color
  106.                    if col.len() == self.colors_count[&c] {
  107.                        // Column with all the entries of a single color
  108.                        score += 1000 * self.state.len();
  109.                    } else {
  110.                        score += 100 * self.state.len();
  111.                        done = false;
  112.                    }
  113.                } else {
  114.                    done = false;
  115.                }
  116.            } else {
  117.                // Empty column
  118.                score += 10 * self.state.len();
  119.            }
  120.        }
  121.  
  122.        if done {
  123.            return Score::Win;
  124.        }
  125.        Score::Score(score)
  126.    }
  127.  
  128.    fn column_moves(&self, col: usize) -> Vec<Move> {
  129.        let mut moves = Vec::new();
  130.        let src = &self.state[col];
  131.  
  132.        let Some(&c) = src.last() else {
  133.            return Vec::new();
  134.        };
  135.  
  136.        for (i, dst) in self.state.iter().enumerate() {
  137.            if i == col {
  138.                continue;
  139.            }
  140.            if dst.last().is_some_and(|&c2| c2 != c) {
  141.                continue;
  142.            }
  143.            if dst.len() < self.column_size {
  144.                moves.push(Move(col, i))
  145.            }
  146.        }
  147.        moves
  148.    }
  149.  
  150.    fn moves(&self) -> Vec<Move> {
  151.        let mut moves = Vec::new();
  152.  
  153.        for i in 0..self.state.len() {
  154.            moves.extend(&self.column_moves(i));
  155.        }
  156.        moves
  157.    }
  158.  
  159.    fn do_move(&mut self, Move(from, to): Move) {
  160.        let &color = self.state[from]
  161.            .last()
  162.            .expect("cannot move from an empty column");
  163.  
  164.        while self.state[to].len() < self.column_size
  165.            && let Some(c) = self.state[from].pop_if(|c2| *c2 == color)
  166.        {
  167.            self.state[to].push(c);
  168.        }
  169.    }
  170.  
  171.    fn moves_tree(&self, depth: u32) -> MoveTree {
  172.        MoveTree {
  173.            game: self.clone(),
  174.            children: self.moves_map(depth),
  175.        }
  176.    }
  177.  
  178.    fn moves_map(&self, depth: u32) -> HashMap<Move, MoveTree> {
  179.        if depth == 0 {
  180.            return HashMap::new();
  181.        }
  182.  
  183.        let mut children = HashMap::new();
  184.  
  185.        for &m in &self.moves() {
  186.            let mut game = self.clone();
  187.            game.do_move(m);
  188.            let map = game.moves_map(depth - 1);
  189.            children.insert(
  190.                m,
  191.                MoveTree {
  192.                    game,
  193.                    children: map,
  194.                },
  195.            );
  196.        }
  197.        children
  198.    }
  199.  
  200.    fn solve(&self, depth: u32, iterations: u32) -> Vec<Move> {
  201.        let mut count = 0;
  202.        let mut game = &self.clone();
  203.        let mut moves = Vec::new();
  204.        let mut tree;
  205.        while count < iterations {
  206.            tree = game.moves_tree(depth);
  207.            let (new_game, score, next_moves) = tree.find_best();
  208.            moves.extend(&next_moves);
  209.  
  210.            if let Score::Win = score {
  211.                break;
  212.            }
  213.            game = new_game;
  214.            count += 1;
  215.        }
  216.        moves
  217.    }
  218. }
  219.  
  220. impl MoveTree {
  221.    fn find_best(&self) -> (&Puzzle, Score, Vec<Move>) {
  222.        let game = &self.game;
  223.        let score = game.rank();
  224.  
  225.        // Using matches!() here because you cannot group if let with another condition
  226.        // using the || operator (although it is allowed with &&).
  227.        if matches!(score, Score::Win) || self.children.is_empty() {
  228.            return (game, score, Vec::new());
  229.        }
  230.  
  231.        let mut best_score = Score::Score(0);
  232.        let mut best_moves = Vec::new();
  233.        let mut best_game = game;
  234.  
  235.        for (&m, tree) in &self.children {
  236.            let (new_game, score, moves) = tree.find_best();
  237.            if score > best_score {
  238.                best_score = score;
  239.                best_moves = vec![m];
  240.                best_moves.extend(&moves);
  241.                best_game = new_game;
  242.            }
  243.            if let Score::Win = best_score {
  244.                break;
  245.            }
  246.        }
  247.        (best_game, best_score, best_moves)
  248.    }
  249. }
  250.  
  251. fn main() {
  252.    let mut p = Puzzle::new(
  253.        4,
  254.        &[vec![1, 2, 3, 4], vec![1, 2, 3, 4], vec![], vec![], vec![]],
  255.    );
  256.    let moves = p.solve(5, 100);
  257.    println!("Initial state: {p}");
  258.    for m in moves {
  259.        println!("{m:?}");
  260.        p.do_move(m);
  261.        println!("-> {p}");
  262.    }
  263. }
Advertisement
Add Comment
Please, Sign In to add comment