~prma/ddd

ffd97060a06738d8795c6a39f43c834f8e9c5da3 — Perma Alesheikh 5 months ago 9797e45
add group questioning and repeating question

This is commit adds ability to ask one round of questions of the next
group.

Also this update causes each question that was answered incorrectly to
be asked immediate again.

Signed-off-by: Perma Alesheikh <me@prma.dev>
6 files changed, 88 insertions(+), 36 deletions(-)

M Cargo.lock
M Cargo.toml
M src/arugments.rs
M src/commands.rs
M src/history.rs
M src/main.rs
M Cargo.lock => Cargo.lock +1 -1
@@ 306,7 306,7 @@ dependencies = [

[[package]]
name = "der_die_das"
version = "0.2.1"
version = "0.2.2"
dependencies = [
 "clap",
 "clap_complete_command",

M Cargo.toml => Cargo.toml +1 -1
@@ 1,6 1,6 @@
[package]
name = "der_die_das"
version = "0.2.2"
version = "0.2.3"
edition = "2021"
authors = ["Perma Alesheikh <me@prma.dev>"]
license = "EUPL-1.2"

M src/arugments.rs => src/arugments.rs +1 -0
@@ 60,6 60,7 @@ pub enum ListCommands {
#[derive(Clone, Debug, Subcommand)]
pub enum AskCommands {
    Nouns,
    Group,
}

#[derive(Clone, Debug, Subcommand)]

M src/commands.rs => src/commands.rs +63 -30
@@ 153,34 153,21 @@ impl StringValidator for ValidateLastWordShouldMatchTheSpelling {
    }
}

pub fn ask_next(storage: Storage, group_config: GroupConfig) -> Result<()> {
    let nouns = storage.all_nouns()?;
    let attempts = storage.all_attempts()?;
    let h = History { nouns, attempts };

    let chosen = if group_config.enable {
        h.next_with_group(group_config.threshold)
    } else {
        h.next()
    }
    .ok_or_eyre("there are no words available for asking. Have you added some?")?;

    let prompt = format!("{} {}\n>", "___".reversed(), chosen.0.word.reversed());
fn ask_noun(storage: &Storage, noun: &Noun) -> Result<()> {
    let prompt = format!("{} {}\n>", "___".reversed(), noun.word.reversed());
    let resp = inquire::Text::new(&prompt)
        .with_help_message(&chosen.0.meaning)
        .with_help_message(&noun.meaning)
        .with_validators(&[
            Box::new(ValidateShouldBeTwoWords {}),
            Box::new(ValidateFirstWordShouldBeArticle {}),
            Box::new(ValidateLastWordShouldMatchTheSpelling(chosen.0.word)),
            Box::new(ValidateLastWordShouldMatchTheSpelling(noun.word.to_owned())),
        ])
        .prompt()?
        .to_owned();

    let resp: Vec<_> = resp.split_whitespace().collect();
    if resp.len() != 2 {
        return Err(eyre!("response is more than two words!"));
    }

    let article = match resp
        .first()
        .ok_or_eyre("something impossible happend!")?


@@ 194,14 181,12 @@ pub fn ask_next(storage: Storage, group_config: GroupConfig) -> Result<()> {
    }?;

    let now = time::OffsetDateTime::now_utc();
    if !chosen.0.articles.contains(&article) {
    if !noun.articles.contains(&article) {
        println!("{}", "Article did not match!".red());
        println!(
            "correct article(s) is(are):\t{}",
            chosen
                .0
                .articles
                .into_iter()
            noun.articles
                .iter()
                .map(|s| s.to_string())
                .collect::<Vec<_>>()
                .join(", ")


@@ 211,35 196,83 @@ pub fn ask_next(storage: Storage, group_config: GroupConfig) -> Result<()> {
        storage.save_attempt(Attempt {
            id: now.unix_timestamp_nanos(),
            at: now,
            for_word: chosen.0.id,
            for_word: noun.id,
            what_happened: der_die_das::attempt::AttemptResult::WrongArticle(article),
        })?;
        ask_noun(storage, noun)
    } else {
        storage.save_attempt(Attempt {
            id: now.unix_timestamp_nanos(),
            at: now,
            for_word: chosen.0.id,
            for_word: noun.id,
            what_happened: der_die_das::attempt::AttemptResult::Success,
        })?;
        println!("{}", "Correct!".green().bold());
    };
        Ok(())
    }
}

fn get_confidence(storage: &Storage, id: i128) -> Result<(Noun, u8)> {
    let nouns = storage.all_nouns()?;
    let attempts = storage.all_attempts()?;
    let h = History { nouns, attempts };
    let word_with_new_confidence = h
        .confidence_map()
    h.confidence_map()
        .into_iter()
        .find(|(n, _)| n.id == chosen.0.id)
        .ok_or_eyre("Some how the word is not there any more!")?;
        .find(|(n, _)| n.id == id)
        .ok_or_eyre("Some how the word is not there any more!")
}

pub fn ask_next(storage: &Storage, group_config: GroupConfig) -> Result<()> {
    let nouns = storage.all_nouns()?;
    let attempts = storage.all_attempts()?;
    let h = History { nouns, attempts };

    let chosen = if group_config.enable {
        h.next_with_group(group_config.threshold)
    } else {
        h.next()
    }
    .ok_or_eyre("there are no words available for asking. Have you added some?")?;

    ask_noun(storage, &chosen.0)?;

    let (_, conf) = get_confidence(storage, chosen.0.id)?;

    println!(
        "The confidence for the word is now at {}.",
        word_with_new_confidence.1.to_string().bold().reversed()
        conf.to_string().bold().reversed()
    );

    Ok(())
}

pub fn group_ask(storage: &Storage, group_config: GroupConfig) -> Result<()> {
    let nouns = storage.all_nouns()?;
    let attempts = storage.all_attempts()?;
    let h = History { nouns, attempts };

    let gr = h
        .next_group(group_config.threshold)
        .ok_or_eyre("You don't have any words yet.")?;

    let number_of_words_in_gr = gr.len();
    gr.into_iter().enumerate().try_for_each(|(i, (noun, _))| {
        println!();
        println!("{}/{}", (i + 1).bold(), number_of_words_in_gr);

        ask_noun(storage, &noun)?;

        let (_, conf) = get_confidence(storage, noun.id)?;

        println!(
            "The confidence for the word is now at {}.",
            conf.to_string().bold().reversed()
        );

        Ok(())
    })
}

pub fn import_nouns(storage: Storage, at: PathBuf) -> Result<()> {
    if !at.try_exists()? {
        return Err(eyre!(format!(

M src/history.rs => src/history.rs +20 -0
@@ 69,6 69,25 @@ impl History {

        sets.first().cloned()
    }
    pub fn next_group(&self, threshold: u8) -> Option<Vec<(Noun, u8)>> {
        let sets = self.grouped_confidence_map();
        if sets.is_empty() {
            return None;
        }
        let under_threshold: HashMap<_, _> = sets
            .into_iter()
            .filter(|(_, nouns)| nouns.iter().any(|(_, c)| c <= &threshold))
            .collect();

        if under_threshold.is_empty() {
            return self.next_group(u8::MAX);
        }
        let mut ks: Vec<_> = under_threshold.keys().collect();
        ks.sort_unstable();
        let mut left = under_threshold.get(ks.first()?.to_owned())?.to_owned();
        left.sort_unstable_by_key(|s| s.1);
        Some(left)
    }

    pub fn next_with_group(&self, threshold: u8) -> Option<(Noun, u8)> {
        let sets = self.grouped_confidence_map();


@@ 84,6 103,7 @@ impl History {
        if under_threshold.is_empty() {
            return self.next_with_group(u8::MAX);
        }

        let mut ks: Vec<_> = under_threshold.keys().collect();
        ks.sort_unstable();
        let mut left = under_threshold.get(ks.first()?.to_owned())?.to_owned();

M src/main.rs => src/main.rs +2 -4
@@ 58,14 58,12 @@ fn main() -> Result<()> {
            Commands::List(list_commands) => match list_commands {
                arugments::ListCommands::Nouns => commands::list_nouns(storage),
            },
            // Commands::Ask(ask_commands) => match ask_commands {
            //     arugments::AskCommands::Nouns => commands::ask_noun(storage),
            // },
            Commands::Import(import_commands) => match import_commands {
                arugments::ImportCommands::Nouns { at } => commands::import_nouns(storage, at),
            },
            Commands::Ask(ask_commands) => match ask_commands {
                arugments::AskCommands::Nouns => commands::ask_next(storage, configs.group),
                arugments::AskCommands::Nouns => commands::ask_next(&storage, configs.group),
                arugments::AskCommands::Group => commands::group_ask(&storage, configs.group),
            },
        },
        None => todo!(),