Skip to content

Commit 829c5cd

Browse files
committed
track total solutions
1 parent 904557d commit 829c5cd

6 files changed

Lines changed: 71 additions & 10 deletions

File tree

solitaire-game/src/lib.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use bevy::{camera::ScalingMode, prelude::*};
22
use bevy_vector_shapes::{prelude::ShapePainter, shapes::DiscPainter};
3-
use solitaire_solver::Board;
3+
use solitaire_solver::{Board, Solution};
44

55
use crate::{
66
animation::PegAnimation,
@@ -71,6 +71,20 @@ fn update_solution(move_event: On<MoveEvent>, mut solution: ResMut<CurrentSoluti
7171
solution.1.push(*move_event);
7272
}
7373

74+
fn trigger_solution(
75+
_: On<MoveEvent>,
76+
board: Res<CurrentBoard>,
77+
solution: Res<CurrentSolution>,
78+
mut commands: Commands,
79+
) {
80+
if board.0.is_solved() {
81+
commands.trigger(SolutionEvent(solution.0.clone()));
82+
}
83+
}
84+
85+
#[derive(Event)]
86+
pub struct SolutionEvent(solitaire_solver::Solution);
87+
7488
#[derive(Default, Resource)]
7589
struct CurrentSolution(solitaire_solver::Solution, Vec<MoveEvent>);
7690

@@ -103,6 +117,7 @@ impl Plugin for PegSolitaire {
103117
app.add_plugins(Buttons);
104118

105119
app.add_observer(update_solution);
120+
app.add_observer(trigger_solution);
106121
app.add_systems(Startup, (camera_setup, scale_viewport).chain());
107122
app.add_systems(PostUpdate, highlight_selected);
108123
app.add_systems(PreUpdate, calc_view_port);

solitaire-game/src/stats.rs

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use bevy::{prelude::*, sprite::Anchor, text::TextBounds, window::RequestRedraw};
22

33
use crate::{
4-
BoardPosition, CurrentBoard,
4+
BoardPosition, CurrentBoard, SolutionEvent,
55
solver::{FeasibleConstellations, RandomMoveChances},
66
total_progress::TotalProgress,
77
};
@@ -22,6 +22,7 @@ impl Plugin for StatsPlugin {
2222
app.add_observer(update_next_move_chance);
2323
app.add_observer(update_overall_success);
2424
app.add_observer(update_total_progress);
25+
app.add_observer(update_solution_count);
2526
}
2627
}
2728

@@ -34,6 +35,9 @@ struct NextMoveChanceText;
3435
#[derive(Component)]
3536
struct TotalProgressText;
3637

38+
#[derive(Component)]
39+
struct SolutionText;
40+
3741
#[derive(Component)]
3842
struct OverallSuccessRatio;
3943

@@ -64,6 +68,8 @@ fn add_text(mut commands: Commands, asset_server: Res<AssetServer>) {
6468
Vec3::from((BoardPosition { x: 1, y: 4 }.to_world_space(), 1.)) + Vec3::new(0.5, -0.5, 0.0);
6569
let title_pos_2 =
6670
Vec3::from((BoardPosition { x: 4, y: 1 }.to_world_space(), 1.)) + Vec3::new(0.5, -0.5, 0.0);
71+
let title_pos_3 =
72+
Vec3::from((BoardPosition { x: 1, y: 1 }.to_world_space(), 1.)) + Vec3::new(0.5, -0.5, 0.0);
6773
let text_pos = title_pos - 1.0 * Vec3::Y;
6874
commands
6975
.spawn((
@@ -113,6 +119,20 @@ fn add_text(mut commands: Commands, asset_server: Res<AssetServer>) {
113119
small_font.clone(),
114120
))
115121
.with_child((TextSpan("".into()), small_font.clone()));
122+
commands
123+
.spawn((
124+
Text2d::new("you have found "),
125+
Transform::from_scale(Vec3::new(0.004, 0.004, 0.004)).with_translation(title_pos_3),
126+
small_font.clone(),
127+
TextLayout::new(Justify::Center, LineBreak::WordBoundary),
128+
TextBounds::from(Vec2::new(600.0, 300.0)),
129+
Anchor::BOTTOM_RIGHT,
130+
SolutionText,
131+
))
132+
.with_child((TextSpan(" ? ".into()), large_font.clone()))
133+
.with_child((TextSpan(" solutions, ".into()), small_font.clone()))
134+
.with_child((TextSpan(" ? ".into()), large_font.clone()))
135+
.with_child((TextSpan(" of which are unique!".into()), small_font.clone()));
116136
}
117137

118138
fn update_overall_success(
@@ -193,3 +213,19 @@ fn update_total_progress(
193213
}
194214
request_redraw.write(RequestRedraw);
195215
}
216+
217+
fn update_solution_count(
218+
_: On<UpdateStats>,
219+
total_progress: Res<TotalProgress>,
220+
solution_text: Query<Entity, With<SolutionText>>,
221+
mut writer: TextUiWriter,
222+
mut request_redraw: MessageWriter<RequestRedraw>,
223+
) {
224+
let num_solutions = total_progress.num_solutions;
225+
let num_unique_solutions = total_progress.unique_solutions.len();
226+
for text in solution_text {
227+
*writer.text(text, 1) = format!("{num_solutions}");
228+
*writer.text(text, 3) = format!("{num_unique_solutions}");
229+
}
230+
request_redraw.write(RequestRedraw);
231+
}

solitaire-game/src/total_progress.rs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::collections::HashSet;
2+
13
use bevy::{
24
app::Plugin,
35
ecs::{
@@ -6,9 +8,9 @@ use bevy::{
68
system::{Res, ResMut},
79
},
810
};
9-
use solitaire_solver::{Board, HashSet, Solution};
11+
use solitaire_solver::{Board, Solution};
1012

11-
use crate::{CurrentBoard, MoveEvent};
13+
use crate::{CurrentBoard, MoveEvent, SolutionEvent};
1214

1315
/// This module keeps track of the total progress of the game.
1416
/// We store statistics about which constellations have previously been
@@ -20,14 +22,17 @@ pub struct TotalProgressPlugin;
2022
pub struct TotalProgress {
2123
/// all states that have ever been seen
2224
pub explored_states: HashSet<Board>,
23-
/// all solutions that have ever been found
24-
pub found_solutions: HashSet<Solution>,
25+
/// all unique solutions that have been explored
26+
pub unique_solutions: HashSet<Solution>,
27+
/// number of times the boared has been solved
28+
pub num_solutions: u64,
2529
}
2630

2731
impl Plugin for TotalProgressPlugin {
2832
fn build(&self, app: &mut bevy::app::App) {
2933
app.init_resource::<TotalProgress>();
3034
app.add_observer(update_total_progress);
35+
app.add_observer(update_solutions);
3136
}
3237
}
3338

@@ -38,3 +43,8 @@ fn update_total_progress(
3843
) {
3944
total_progress.explored_states.insert(board.0);
4045
}
46+
47+
fn update_solutions(solution: On<SolutionEvent>, mut total_progress: ResMut<TotalProgress>) {
48+
total_progress.unique_solutions.insert(solution.0.clone());
49+
total_progress.num_solutions += 1;
50+
}

solitaire-game/src/window.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ pub struct MainWindow;
99

1010
impl Plugin for MainWindow {
1111
fn build(&self, app: &mut App) {
12-
// app.insert_resource(WinitSettings::desktop_app());
12+
app.insert_resource(WinitSettings::desktop_app());
1313

1414
let default_plugins = DefaultPlugins
1515
.set(LogPlugin {
@@ -24,7 +24,7 @@ impl Plugin for MainWindow {
2424
fit_canvas_to_parent: true,
2525
prevent_default_event_handling: false,
2626
desired_maximum_frame_latency: core::num::NonZero::new(1u32),
27-
present_mode: bevy::window::PresentMode::AutoNoVsync,
27+
present_mode: bevy::window::PresentMode::AutoVsync,
2828
#[cfg(not(target_os = "android"))]
2929
mode: WindowMode::Windowed,
3030
#[cfg(target_os = "android")]

solitaire-solver/src/mov.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::fmt::{Display, Error, Formatter};
33

44
use crate::{Dir, board};
55

6-
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
6+
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
77
pub struct Move {
88
pub pos: (Idx, Idx),
99
pub skip: (Idx, Idx),

solitaire-solver/src/solution.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::fmt::{Display, Formatter, Result};
22

33
use crate::{Board, Move};
44

5-
#[derive(Clone, Default)]
5+
#[derive(Clone, Default, Debug, PartialEq, Eq, Hash)]
66
pub struct Solution {
77
steps: [Move; 31],
88
count: usize,

0 commit comments

Comments
 (0)