Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
159 changes: 70 additions & 89 deletions src/decision_model/model.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use std::cell::RefCell;

pub enum Side {
Lhs,
Rhs,
Expand All @@ -19,127 +17,119 @@ impl Parameters {
}

pub struct DecisionModel {
parameters: RefCell<Vec<Parameters>>,
indices: RefCell<Vec<(usize, usize)>>,
current_index: RefCell<Option<usize>>,
parameters: Vec<Parameters>,
indices: Vec<(usize, usize)>,
current_index: Option<usize>,
}
impl DecisionModel {
pub fn new() -> Self {
Self {
parameters: RefCell::new(Vec::new()),
indices: RefCell::new(Vec::new()),
current_index: RefCell::new(None),
parameters: Vec::new(),
indices: Vec::new(),
current_index: None,
}
}

pub fn reset(&self) {
let mut params = self.parameters.borrow_mut();
let mut idx = self.indices.borrow_mut();
let mut ci = self.current_index.borrow_mut();
pub fn reset(&mut self) {
// let mut params = self.parameters.borrow_mut();
// let mut idx = self.indices.borrow_mut();
// let mut ci = self.current_index.borrow_mut();

*params = Vec::new();
*idx = Vec::new();
*ci = None;
self.parameters = Vec::new();
self.indices = Vec::new();
self.current_index = None;
}

pub fn move_to_next_pair(&self) {
let mut ci = self.current_index.borrow_mut();
let idx = self.indices.borrow();
pub fn move_to_next_pair(&mut self) {
let ci = self.current_index;

let idx = &self.indices;

if ci.is_some() {
match idx.get(ci.unwrap() + 1) {
Some(_) => *ci = Some(ci.unwrap() + 1),
None => *ci = None,
Some(_) => self.current_index = Some(ci.unwrap() + 1),
None => self.current_index = None,
};
}
}

pub fn get_current_pair(&self) -> Option<(Parameters, Parameters)> {
let ci = self.current_index.borrow();
let params = self.parameters.borrow();
let idx = self.indices.borrow();
match *ci {
Some(p) => Some((params[idx[p].0].clone(), params[idx[p].1].clone())),
None => None,
}
pub fn get_current_pair(&mut self) -> Option<(Parameters, Parameters)> {
self.current_index.map(|p| {
(
self.parameters[self.indices[p].0].clone(),
self.parameters[self.indices[p].1].clone(),
)
})
}

pub fn record_score_of_current_pair(&self, winner: Side, points_to_add: u32) {
let ci = self.current_index.borrow();
let mut params = self.parameters.borrow_mut();
let idx = self.indices.borrow();
pub fn record_score_of_current_pair(&mut self, winner: Side, points_to_add: u32) {
let ci = self.current_index;

if ci.is_some() {
match winner {
Side::Lhs => {
params[idx[ci.unwrap()].0].score += points_to_add;
self.parameters[self.indices[ci.unwrap()].0].score += points_to_add;
}
Side::Rhs => {
params[idx[ci.unwrap()].1].score += points_to_add;
self.parameters[self.indices[ci.unwrap()].1].score += points_to_add;
}
_ => {}
};
}
}

pub fn prepare_model(&self, param_list: &Vec<String>, randomize: bool) {
let mut parameters = self.parameters.borrow_mut();
pub fn prepare_model(&mut self, param_list: &Vec<String>, randomize: bool) {
for param in param_list {
parameters.push(Parameters {
self.parameters.push(Parameters {
name: param.to_string(),
score: 0,
});
}

parameters.sort_by(|a, b| a.name.cmp(&b.name));
parameters.retain(|i| i.name.ne(""));
parameters.dedup_by(|a, b| a.name.eq_ignore_ascii_case(&b.name));
self.parameters.sort_by(|a, b| a.name.cmp(&b.name));
self.parameters.retain(|i| !i.name.is_empty());
self.parameters
.dedup_by(|a, b| a.name.eq_ignore_ascii_case(&b.name));

let mut indices = self.indices.borrow_mut();
*indices = index_pairs(parameters.len());
self.indices = index_pairs(self.parameters.len());
if randomize {
let mut rng = rand::thread_rng();
rand::seq::SliceRandom::shuffle(&mut indices[..], &mut rng);
rand::seq::SliceRandom::shuffle(&mut self.indices[..], &mut rng);
}

match parameters.len() > 1 {
match self.parameters.len() > 1 {
true => {
let mut ci = self.current_index.borrow_mut();
*ci = Some(0);
self.current_index = Some(0);
}
false => {
let mut ci = self.current_index.borrow_mut();
*ci = None;
self.current_index = None;
}
}
}

pub fn reset_score_and_indices(&self) {
let mut parameters: std::cell::RefMut<Vec<Parameters>> = self.parameters.borrow_mut();
parameters.iter_mut().for_each(|p| p.score = 0);
pub fn reset_score_and_indices(&mut self) {
// let mut parameters: std::cell::RefMut<Vec<Parameters>> = self.parameters.borrow_mut();
self.parameters.iter_mut().for_each(|p| p.score = 0);

if parameters.len() > 1 {
let mut ci = self.current_index.borrow_mut();
*ci = Some(0);
if self.parameters.len() > 1 {
self.current_index = Some(0);
}
}

pub fn is_model_ready_to_play(&self) -> bool {
(self.parameters.borrow().len() >= 2)
&& (self.parameters.borrow().iter().all(|x| x.score == 0))
pub fn is_model_ready_to_play(&mut self) -> bool {
(self.parameters.len() >= 2) && (self.parameters.iter().all(|x| x.score == 0))
}

pub fn get_parameters(&self) -> String {
pub fn get_parameters(&mut self) -> String {
self.parameters
.borrow()
.iter()
.map(|x| x.name.to_string())
.collect::<Vec<_>>()
.join("\n")
}

pub fn sorted_by_score(&self) -> Vec<Parameters> {
let mut params: Vec<Parameters> = self.parameters.borrow().clone();
let mut params = self.parameters.clone();
params.sort_by(|a, b| b.score.cmp(&a.score));
params
}
Expand All @@ -158,7 +148,7 @@ fn index_pairs(matrix_size: usize) -> Vec<(usize, usize)> {
pub fn clean_input(input: &str) -> Vec<String> {
let mut v: Vec<String> = input.split('\n').map(str::to_string).collect();
v = v.into_iter().map(|s| s.trim().to_string()).collect();
v.retain(|i| i.ne(""));
v.retain(|i| !i.is_empty());
v
}

Expand All @@ -168,21 +158,21 @@ mod tests {

#[test]
fn return_sorted() {
let input: Vec<String> = vec!["a", "b", "c"].iter().map(|&s| s.to_string()).collect();
let model = DecisionModel::new();
let input = ["a", "b", "c"].iter().map(|&s| s.to_string()).collect();
let mut model = DecisionModel::new();
model.prepare_model(&input, false);
model.parameters.borrow_mut()[0].score = 1;
model.parameters.borrow_mut()[1].score = 2;
model.parameters.borrow_mut()[2].score = 3;
model.parameters[0].score = 1;
model.parameters[1].score = 2;
model.parameters[2].score = 3;

let result = model.sorted_by_score();
assert_eq!(3, result[0].score);
assert_eq!("c", result[0].name);
}
#[test]
fn model_go_to_next_pair() {
let input: Vec<String> = vec!["a", "b", "c"].iter().map(|&s| s.to_string()).collect();
let model = DecisionModel::new();
let input: Vec<String> = ["a", "b", "c"].iter().map(|&s| s.to_string()).collect();
let mut model = DecisionModel::new();
model.prepare_model(&input, false);
model.move_to_next_pair();

Expand All @@ -192,8 +182,8 @@ mod tests {

#[test]
fn model_increment_score() {
let input: Vec<String> = vec!["a", "b", "c"].iter().map(|&s| s.to_string()).collect();
let model = DecisionModel::new();
let input: Vec<String> = ["a", "b", "c"].iter().map(|&s| s.to_string()).collect();
let mut model = DecisionModel::new();
model.prepare_model(&input, false);

model.record_score_of_current_pair(Side::Rhs, 15);
Expand All @@ -204,9 +194,9 @@ mod tests {

#[test]
fn model_current_pair_good_model() {
let input: Vec<String> = vec!["a", "b", "c"].iter().map(|&s| s.to_string()).collect();
let input: Vec<String> = ["a", "b", "c"].iter().map(|&s| s.to_string()).collect();

let model = DecisionModel::new();
let mut model = DecisionModel::new();
model.prepare_model(&input, false);

assert_eq!(
Expand All @@ -226,45 +216,36 @@ mod tests {

#[test]
fn model_current_pair_bad_model() {
let input: Vec<String> = vec!["a"].iter().map(|&s| s.to_string()).collect();
let input: Vec<String> = ["a"].iter().map(|&s| s.to_string()).collect();

let model = DecisionModel::new();
let mut model = DecisionModel::new();
model.prepare_model(&input, false);

assert_eq!(None, model.get_current_pair());
}

#[test]
fn model_parameter_list() {
let input: Vec<String> = vec!["a", "miao", "x"]
.iter()
.map(|&s| s.to_string())
.collect();
let input: Vec<String> = ["a", "miao", "x"].iter().map(|&s| s.to_string()).collect();

let model = DecisionModel::new();
let mut model = DecisionModel::new();
model.prepare_model(&input, false);

assert_eq!("a\nmiao\nx", model.get_parameters());
}
#[test]
fn model_prepare() {
let input: Vec<String> = vec!["a", "miao", "x"]
.iter()
.map(|&s| s.to_string())
.collect();
let input: Vec<String> = ["a", "miao", "x"].iter().map(|&s| s.to_string()).collect();

let model = DecisionModel::new();
let mut model = DecisionModel::new();
model.prepare_model(&input, false);

assert_eq!(true, model.is_model_ready_to_play());
assert!(model.is_model_ready_to_play());
}

#[test]
fn model_dedupe() {
let expected: Vec<String> = vec!["a", "miao", "x"]
.iter()
.map(|&s| s.to_string())
.collect();
let expected: Vec<String> = ["a", "miao", "x"].iter().map(|&s| s.to_string()).collect();

let input = String::from("a \nmiao\n\nx\n");
let result = clean_input(&input);
Expand Down
29 changes: 16 additions & 13 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,22 @@ mod decision_model;

use decision_model::model as DM;

use std::rc::Rc;
use std::{cell::RefCell, rc::Rc};

use slint::{SharedString, VecModel};
slint::include_modules!();

fn main() {
let main_window = MainWindow::new().unwrap();
let model = Rc::new(DM::DecisionModel::new());
// let model = Rc::new(DM::DecisionModel::new());
let model = Rc::new(RefCell::new(DM::DecisionModel::new()));

let mw = main_window.as_weak();
let mdl = model.clone();
main_window.on_dialog_play(move || {
mdl.reset_score_and_indices();
mdl.borrow_mut().reset_score_and_indices();

let current_pair = mdl.get_current_pair().unwrap();
let current_pair = mdl.borrow_mut().get_current_pair().unwrap();

mw.unwrap()
.set_lhs_param_name(current_pair.0.get_name_and_score().0.into());
Expand All @@ -29,14 +30,14 @@ fn main() {
let mw = main_window.as_weak();
let mdl = model.clone();
main_window.on_dialog_return_edit(move || {
mdl.reset_score_and_indices();
mdl.borrow_mut().reset_score_and_indices();
View::Edit.set_visible(&mw.unwrap())
});

let mw = main_window.as_weak();
let mdl = model.clone();
main_window.on_dialog_results(move || {
let params = mdl.sorted_by_score();
let params = mdl.borrow_mut().sorted_by_score();
let vm = Rc::new(VecModel::<Parameter>::default());

vm.extend(params.into_iter().map(|i| Parameter {
Expand All @@ -58,11 +59,12 @@ fn main() {
_ => DM::Side::Other,
};

mdl.record_score_of_current_pair(winner_side, 1);
mdl.borrow_mut()
.record_score_of_current_pair(winner_side, 1);

mdl.move_to_next_pair();
mdl.borrow_mut().move_to_next_pair();

match mdl.get_current_pair() {
match mdl.borrow_mut().get_current_pair() {
Some(p) => {
mw.unwrap()
.set_lhs_param_name(p.0.get_name_and_score().0.into());
Expand All @@ -80,7 +82,8 @@ fn main() {
let mw = main_window.as_weak();
let mdl = model.clone();
main_window.on_show(move || {
mw.unwrap().set_parameters(mdl.get_parameters().into());
mw.unwrap()
.set_parameters(mdl.borrow_mut().get_parameters().into());
});

let mw = main_window.as_weak();
Expand All @@ -89,7 +92,7 @@ fn main() {
mw.unwrap().set_parameters(SharedString::new());
mw.unwrap().set_play_enabled(false);

mdl.reset();
mdl.borrow_mut().reset();
});

let mw = main_window.as_weak();
Expand All @@ -99,9 +102,9 @@ fn main() {
println!("add params clicked:\n{}", parameters_ui);

let parameter_list = DM::clean_input(&parameters_ui);
mdl.prepare_model(&parameter_list, true);
mdl.borrow_mut().prepare_model(&parameter_list, true);

if mdl.is_model_ready_to_play() {
if mdl.borrow_mut().is_model_ready_to_play() {
mw.unwrap().set_play_enabled(true);
}
});
Expand Down