Skip to content

Commit b2b54f1

Browse files
committed
add unique paths calculation
1 parent bae76e3 commit b2b54f1

6 files changed

Lines changed: 43 additions & 7 deletions

File tree

solitaire-game/src/total_progress.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ fn update_total_progress(
8080
.normalized_explored_states
8181
.entry(board.normalize())
8282
.or_insert(Default::default()) += 1;
83-
total_progress.explored_states_by_pegs[board.count_balls() as usize - 1].insert(board);
83+
total_progress.explored_states_by_pegs[board.count_pegs() as usize - 1].insert(board);
8484
}
8585
}
8686
}

solitaire-solver/src/board.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -357,8 +357,8 @@ impl Board {
357357
self.movable_positions(dir) & self & !self.dir_shift(dir, 1) & !self.dir_shift(dir, 2)
358358
}
359359

360-
pub const fn count_balls(&self) -> u64 {
361-
self.0.count_ones() as u64
360+
pub const fn count_pegs(&self) -> usize {
361+
self.0.count_ones() as usize
362362
}
363363

364364
#[inline(always)]

solitaire-solver/src/calc_success.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ pub fn calculate_p_random_chance_success(feasible: Vec<Board>) -> HashMap<Board,
1212
let feasible_with_i_pegs = feasible
1313
.iter()
1414
.copied()
15-
.filter(|b| b.count_balls() == i as u64)
15+
.filter(|b| b.count_pegs() == i)
1616
.collect::<Vec<_>>();
1717
for constellation in feasible_with_i_pegs {
1818
let legal_moves = constellation.get_legal_moves();

solitaire-solver/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ pub use hash::{CustomHashMap as HashMap, CustomHashSet as HashSet};
2828
pub use mov::Move;
2929
pub use solution::{Solution, SolutionMultiset};
3030

31-
pub use unique_solutions::all_unique_solutions;
31+
pub use unique_solutions::{all_unique_paths, all_unique_solutions};
3232

3333
use crate::sort::Sort;
3434

solitaire-solver/src/unique_solutions.rs

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::solution::SolutionMultiset;
2-
use crate::{Board, Move};
2+
use crate::{Board, Move, normalize};
33
use crate::{HashSet, Solution};
4+
use std::array;
45
use std::collections::BTreeMap;
56

67
/// we define two solutions as "equal" when the
@@ -137,4 +138,31 @@ impl ZobristTable {
137138
type MultisetHash = u64;
138139

139140
#[allow(unused)]
140-
pub fn all_unique_paths(feasible: &HashSet<Board>) {}
141+
pub fn all_unique_paths(feasible: impl IntoIterator<Item = Board>) -> HashMap<Board, usize> {
142+
let mut number_of_combinations: HashMap<Board, usize, _> = HashMap::new();
143+
let mut boards: [Vec<Board>; 33] = array::from_fn(|_| Default::default());
144+
let mut feasible_set: HashSet<Board> = HashSet::default();
145+
for board in feasible.into_iter() {
146+
feasible_set.insert(board);
147+
boards[board.count_pegs()].push(board);
148+
}
149+
number_of_combinations.insert(Board::solved(), 1);
150+
for i in 2..=32 {
151+
for board in &boards[i] {
152+
let mut next = Board::possible_moves(&[*board]);
153+
normalize(&mut next);
154+
next.dedup();
155+
156+
let count = next
157+
.into_iter()
158+
.filter(|b| feasible_set.contains(b))
159+
.map(|b| number_of_combinations[&b])
160+
.sum();
161+
let entry = number_of_combinations
162+
.entry(*board)
163+
.or_insert(Default::default());
164+
*entry = count;
165+
}
166+
}
167+
number_of_combinations
168+
}

src/main.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ enum Command {
3030
CalculateRandomChanceSuccessRatio,
3131
/// calculate unique solutions
3232
UniqueSolutions,
33+
/// calculate unique paths of solutions
34+
UniquePaths,
3335
}
3436

3537
fn main() {
@@ -85,6 +87,12 @@ fn main() {
8587
solitaire_solver::all_unique_solutions(Board::default(), feasible.into_iter());
8688
log::info!("unique solutions: {}", solutions.len());
8789
}
90+
Command::UniquePaths => {
91+
let feasible = solitaire_solver::calculate_all_solutions(None);
92+
log::info!("feasible: {}", feasible.len());
93+
let paths = solitaire_solver::all_unique_paths(feasible);
94+
log::info!("unique paths: {}", paths.get(&Board::default()).unwrap());
95+
}
8896
},
8997
None => {
9098
#[cfg(feature = "game")]

0 commit comments

Comments
 (0)