Add solution

This commit is contained in:
hal8174 2024-08-05 13:04:16 +02:00
parent 915b486dc1
commit 780e817337
5 changed files with 1047 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/target

16
Cargo.lock generated Normal file
View file

@ -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"

7
Cargo.toml Normal file
View file

@ -0,0 +1,7 @@
[package]
name = "laulens_move"
version = "0.1.0"
edition = "2021"
[dependencies]
smallvec = "1.13.2"

678
out.txt Normal file
View file

@ -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

345
src/main.rs Normal file
View file

@ -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<u64, (u64, Move)>, 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);
}
}