From 780e817337cb65246d2ef61a061a657a10c41faa Mon Sep 17 00:00:00 2001 From: hal8174 Date: Mon, 5 Aug 2024 13:04:16 +0200 Subject: [PATCH] Add solution --- .gitignore | 1 + Cargo.lock | 16 ++ Cargo.toml | 7 + out.txt | 678 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 345 ++++++++++++++++++++++++++ 5 files changed, 1047 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 out.txt create mode 100644 src/main.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..81a4b57 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,16 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "laulens_move" +version = "0.1.0" +dependencies = [ + "smallvec", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..7951646 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "laulens_move" +version = "0.1.0" +edition = "2021" + +[dependencies] +smallvec = "1.13.2" diff --git a/out.txt b/out.txt new file mode 100644 index 0000000..454127c --- /dev/null +++ b/out.txt @@ -0,0 +1,678 @@ +11022 +33456 +33478 +990aa + +Move: 4 Up +11422 +33456 +33078 +990aa + +Move: 7 Left +11422 +33456 +33708 +990aa + +Move: 7 Down +11422 +33456 +33008 +997aa + +Move: 4 Down +11022 +33456 +33408 +997aa + +Move: 2 Left +11220 +33456 +33408 +997aa + +Move: 6 Up +11226 +33450 +33408 +997aa + +Move: 8 Up +11226 +33458 +33400 +997aa + +Move: 10 Up +11226 +33458 +334aa +99700 + +Move: 7 Right +11226 +33458 +334aa +99070 + +Move: 4 Down +11226 +33058 +334aa +99470 + +Move: 5 Left +11226 +33508 +334aa +99470 + +Move: 7 Right +11226 +33508 +334aa +99407 + +Move: 8 Left +11226 +33580 +334aa +99407 + +Move: 6 Down +11220 +33586 +334aa +99407 + +Move: 2 Right +11022 +33586 +334aa +99407 + +Move: 5 Up +11522 +33086 +334aa +99407 + +Move: 4 Up +11522 +33486 +334aa +99007 + +Move: 9 Right +11522 +33486 +334aa +09907 + +Move: 9 Right +11522 +33486 +334aa +00997 + +Move: 3 Down +11522 +00486 +334aa +33997 + +Move: 1 Down +00522 +11486 +334aa +33997 + +Move: 5 Left +05022 +11486 +334aa +33997 + +Move: 2 Left +05220 +11486 +334aa +33997 + +Move: 5 Left +50220 +11486 +334aa +33997 + +Move: 2 Left +52200 +11486 +334aa +33997 + +Move: 6 Up +52206 +11480 +334aa +33997 + +Move: 8 Up +52286 +11400 +334aa +33997 + +Move: 10 Up +52286 +114aa +33400 +33997 + +Move: 7 Up +52286 +114aa +33407 +33990 + +Move: 7 Left +52286 +114aa +33470 +33990 + +Move: 9 Right +52286 +114aa +33470 +33099 + +Move: 4 Down +52286 +110aa +33470 +33499 + +Move: 10 Left +52286 +11aa0 +33470 +33499 + +Move: 6 Down +52280 +11aa6 +33470 +33499 + +Move: 6 Down +52280 +11aa0 +33476 +33499 + +Move: 10 Right +52280 +110aa +33476 +33499 + +Move: 1 Right +52280 +011aa +33476 +33499 + +Move: 5 Down +02280 +511aa +33476 +33499 + +Move: 2 Left +22080 +511aa +33476 +33499 + +Move: 8 Left +22800 +511aa +33476 +33499 + +Move: 10 Up +228aa +51100 +33476 +33499 + +Move: 1 Right +228aa +50110 +33476 +33499 + +Move: 1 Right +228aa +50011 +33476 +33499 + +Move: 8 Down +220aa +50811 +33476 +33499 + +Move: 8 Left +220aa +58011 +33476 +33499 + +Move: 4 Up +220aa +58411 +33476 +33099 + +Move: 4 Up +224aa +58411 +33076 +33099 + +Move: 9 Left +224aa +58411 +33076 +33990 + +Move: 6 Down +224aa +58411 +33070 +33996 + +Move: 7 Right +224aa +58411 +33007 +33996 + +Move: 9 Up +224aa +58411 +33997 +33006 + +Move: 6 Left +224aa +58411 +33997 +33060 + +Move: 7 Down +224aa +58411 +33990 +33067 + +Move: 9 Right +224aa +58411 +33099 +33067 + +Move: 4 Down +220aa +58411 +33499 +33067 + +Move: 2 Right +022aa +58411 +33499 +33067 + +Move: 4 Down +022aa +58011 +33499 +33467 + +Move: 1 Left +022aa +58110 +33499 +33467 + +Move: 5 Up +522aa +08110 +33499 +33467 + +Move: 8 Left +522aa +80110 +33499 +33467 + +Move: 1 Left +522aa +81100 +33499 +33467 + +Move: 9 Up +522aa +81199 +33400 +33467 + +Move: 6 Up +522aa +81199 +33460 +33407 + +Move: 6 Right +522aa +81199 +33406 +33407 + +Move: 4 Right +522aa +81199 +33046 +33047 + +Move: 3 Right +522aa +81199 +03346 +03347 + +Move: 8 Down +522aa +01199 +83346 +03347 + +Move: 5 Down +022aa +51199 +83346 +03347 + +Move: 2 Left +220aa +51199 +83346 +03347 + +Move: 8 Down +220aa +51199 +03346 +83347 + +Move: 5 Down +220aa +01199 +53346 +83347 + +Move: 1 Left +220aa +11099 +53346 +83347 + +Move: 9 Left +220aa +11990 +53346 +83347 + +Move: 6 Up +220aa +11996 +53340 +83347 + +Move: 7 Up +220aa +11996 +53347 +83340 + +Move: 10 Left +22aa0 +11996 +53347 +83340 + +Move: 6 Up +22aa6 +11990 +53347 +83340 + +Move: 7 Up +22aa6 +11997 +53340 +83340 + +Move: 4 Right +22aa6 +11997 +53304 +83304 + +Move: 3 Right +22aa6 +11997 +50334 +80334 + +Move: 5 Right +22aa6 +11997 +05334 +80334 + +Move: 5 Down +22aa6 +11997 +00334 +85334 + +Move: 1 Down +22aa6 +00997 +11334 +85334 + +Move: 9 Left +22aa6 +09907 +11334 +85334 + +Move: 9 Left +22aa6 +99007 +11334 +85334 + +Move: 3 Up +22aa6 +99337 +11334 +85004 + +Move: 5 Right +22aa6 +99337 +11334 +80504 + +Move: 5 Right +22aa6 +99337 +11334 +80054 + +Move: 8 Right +22aa6 +99337 +11334 +08054 + +Move: 8 Right +22aa6 +99337 +11334 +00854 + +Move: 1 Down +22aa6 +99337 +00334 +11854 + +Move: 9 Down +22aa6 +00337 +99334 +11854 + +Move: 2 Down +00aa6 +22337 +99334 +11854 + +Move: 10 Left +0aa06 +22337 +99334 +11854 + +Move: 10 Left +aa006 +22337 +99334 +11854 + +Move: 3 Up +aa336 +22337 +99004 +11854 + +Move: 5 Up +aa336 +22337 +99054 +11804 + +Move: 5 Left +aa336 +22337 +99504 +11804 + +Move: 4 Left +aa336 +22337 +99540 +11840 + +Move: 7 Down +aa336 +22330 +99547 +11840 + +Move: 6 Down +aa330 +22336 +99547 +11840 + +Move: 7 Down +aa330 +22336 +99540 +11847 + +Move: 6 Down +aa330 +22330 +99546 +11847 + +Move: 3 Right +aa033 +22033 +99546 +11847 + +Move: 5 Up +aa033 +22533 +99046 +11847 + +Move: 5 Up +aa533 +22033 +99046 +11847 + +Move: 8 Up +aa533 +22033 +99846 +11047 + +Move: 8 Up +aa533 +22833 +99046 +11047 + +Move: 4 Left +aa533 +22833 +99406 +11407 + +Move: 6 Left +aa533 +22833 +99460 +11407 + +Move: 6 Down +aa533 +22833 +99400 +11467 + +Move: 3 Down +aa500 +22833 +99433 +11467 + +Length: 112 diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..3efd7ae --- /dev/null +++ b/src/main.rs @@ -0,0 +1,345 @@ +use smallvec::SmallVec; +use std::collections::{hash_map::Entry::Vacant, HashMap, VecDeque}; + +#[derive(Debug, Clone, Copy)] +struct Board { + board: [[u8; 5]; 4], + pieces: [[u8; 2]; 11], +} + +impl Board { + fn new() -> Self { + Self { + board: [ + [1, 1, 0, 2, 2], + [3, 3, 4, 5, 6], + [3, 3, 4, 7, 8], + [9, 9, 0, 10, 10], + ], + pieces: [ + [0, 0], + [0, 0], + [3, 0], + [0, 1], + [2, 1], + [3, 1], + [4, 1], + [3, 2], + [4, 2], + [0, 3], + [3, 3], + ], + } + } + + fn apply_move(&mut self, m: &Move) { + let pos = self.pieces[m.piece as usize]; + let tiles: &[[u8; 2]] = match &m.piece { + 1 | 2 | 9 | 10 => &[[0, 0], [1, 0]], + 3 => &[[0, 0], [1, 0], [0, 1], [1, 1]], + 4 => &[[0, 0], [0, 1]], + 5..=8 => &[[0, 0]], + _ => unreachable!(), + }; + + for [x, y] in tiles { + self.board[(pos[1] + y) as usize][(pos[0] + x) as usize] = 0; + } + + let newpos = match &m.dir { + Dir::Up => [pos[0], pos[1] - 1], + Dir::Right => [pos[0] + 1, pos[1]], + Dir::Down => [pos[0], pos[1] + 1], + Dir::Left => [pos[0] - 1, pos[1]], + }; + + for [x, y] in tiles { + self.board[(newpos[1] + y) as usize][(newpos[0] + x) as usize] = m.piece; + } + + self.pieces[m.piece as usize] = newpos; + } + + fn revert_move(&mut self, m: &Move) { + let im = Move { + dir: match m.dir { + Dir::Up => Dir::Down, + Dir::Right => Dir::Left, + Dir::Down => Dir::Up, + Dir::Left => Dir::Right, + }, + piece: m.piece, + }; + self.apply_move(&im); + } + + fn get_hash(&self) -> u64 { + let mut r = 0; + let p = self.pieces[3]; + r |= (p[0] << 2 | p[1]) as u64; + let p = self.pieces[4]; + r |= ((p[0] << 2 | p[1]) as u64) << 5; + + let mut p = [ + self.pieces[1], + self.pieces[2], + self.pieces[9], + self.pieces[10], + ]; + p.sort(); + for (i, p) in p.into_iter().enumerate() { + r |= ((p[0] << 2 | p[1]) as u64) << (i * 5 + 10); + } + + let mut p = [ + self.pieces[5], + self.pieces[6], + self.pieces[7], + self.pieces[8], + ]; + p.sort(); + for (i, p) in p.into_iter().enumerate() { + r |= ((p[0] << 2 | p[1]) as u64) << (i * 5 + 30); + } + + r + } + + fn possible_moves(&self) -> SmallVec<[Move; 8]> { + let mut v = SmallVec::new(); + + for i in 1..=10 { + let [px, py] = self.pieces[i as usize]; + match i { + 1 | 2 | 9 | 10 => { + if px > 0 && self.board[py as usize][(px - 1) as usize] == 0 { + v.push(Move { + dir: Dir::Left, + piece: i, + }); + } + + if px < 3 && self.board[py as usize][(px + 2) as usize] == 0 { + v.push(Move { + dir: Dir::Right, + piece: i, + }); + } + + if py > 0 + && self.board[(py - 1) as usize][px as usize] == 0 + && self.board[(py - 1) as usize][(px + 1) as usize] == 0 + { + v.push(Move { + dir: Dir::Up, + piece: i, + }); + } + + if py < 3 + && self.board[(py + 1) as usize][px as usize] == 0 + && self.board[(py + 1) as usize][(px + 1) as usize] == 0 + { + v.push(Move { + dir: Dir::Down, + piece: i, + }); + } + } + 3 => { + if px > 0 + && self.board[py as usize][(px - 1) as usize] == 0 + && self.board[(py + 1) as usize][(px - 1) as usize] == 0 + { + v.push(Move { + dir: Dir::Left, + piece: i, + }); + } + + if px < 3 + && self.board[py as usize][(px + 2) as usize] == 0 + && self.board[(py + 1) as usize][(px + 2) as usize] == 0 + { + v.push(Move { + dir: Dir::Right, + piece: i, + }); + } + if py > 0 + && self.board[(py - 1) as usize][px as usize] == 0 + && self.board[(py - 1) as usize][(px + 1) as usize] == 0 + { + v.push(Move { + dir: Dir::Up, + piece: i, + }); + } + + if py < 2 + && self.board[(py + 2) as usize][px as usize] == 0 + && self.board[(py + 2) as usize][(px + 1) as usize] == 0 + { + v.push(Move { + dir: Dir::Down, + piece: i, + }); + } + } + 4 => { + if px > 0 + && self.board[py as usize][(px - 1) as usize] == 0 + && self.board[(py + 1) as usize][(px - 1) as usize] == 0 + { + v.push(Move { + dir: Dir::Left, + piece: i, + }); + } + + if px < 4 + && self.board[py as usize][(px + 1) as usize] == 0 + && self.board[(py + 1) as usize][(px + 1) as usize] == 0 + { + v.push(Move { + dir: Dir::Right, + piece: i, + }); + } + + if py > 0 && self.board[(py - 1) as usize][px as usize] == 0 { + v.push(Move { + dir: Dir::Up, + piece: i, + }); + } + + if py < 2 && self.board[(py + 2) as usize][px as usize] == 0 { + v.push(Move { + dir: Dir::Down, + piece: i, + }); + } + } + 5..=8 => { + if px > 0 && self.board[py as usize][(px - 1) as usize] == 0 { + v.push(Move { + dir: Dir::Left, + piece: i, + }); + } + + if px < 4 && self.board[py as usize][(px + 1) as usize] == 0 { + v.push(Move { + dir: Dir::Right, + piece: i, + }); + } + + if py > 0 && self.board[(py - 1) as usize][px as usize] == 0 { + v.push(Move { + dir: Dir::Up, + piece: i, + }); + } + + if py < 3 && self.board[(py + 1) as usize][px as usize] == 0 { + v.push(Move { + dir: Dir::Down, + piece: i, + }); + } + } + _ => unreachable!(), + } + } + + v + } + + fn print(&self) { + for y in 0..4 { + for x in 0..5 { + print!("{:x}", self.board[y][x]); + } + println!(); + } + println!(); + } +} + +#[derive(Debug, Clone, Copy)] +enum Dir { + Up, + Right, + Down, + Left, +} + +#[derive(Debug, Clone, Copy)] +struct Move { + dir: Dir, + piece: u8, +} + +fn solver() -> Option<(HashMap, Board)> { + let mut solution = HashMap::new(); + let mut queue = VecDeque::new(); + + solution.insert( + Board::new().get_hash(), + ( + 0, + Move { + dir: Dir::Up, + piece: 0, + }, + ), + ); + + queue.push_back(Board::new()); + + while let Some(q) = queue.pop_front() { + let moves = q.possible_moves(); + + for m in moves { + let mut b = q; + + b.apply_move(&m); + + if let Vacant(e) = solution.entry(b.get_hash()) { + e.insert((q.get_hash(), m)); + if b.pieces[3] == [3, 1] { + return Some((solution, b)); + } + queue.push_back(b); + } + } + } + + None +} + +fn main() { + if let Some((s, b)) = solver() { + let mut h = b.get_hash(); + + let mut r = Vec::new(); + while let Some(&(i, m)) = s.get(&h) { + // println!("{:b}", i); + r.push(m); + h = i; + } + + r.reverse(); + + let mut b = Board::new(); + for m in &r[1..] { + b.print(); + b.apply_move(m); + println!("Move: {} {:?}", m.piece, m.dir); + } + b.print(); + println!("Length: {}", r.len() - 1); + } +}