From 429a2b7ccd92f86bfa12427cec508a72731a27fa Mon Sep 17 00:00:00 2001 From: Paulocracy <36934614+Paulocracy@users.noreply.github.com> Date: Fri, 2 Feb 2024 23:51:40 +0100 Subject: [PATCH 1/3] Add question preference options --- config/config.json | 3 ++ learning/learning.json | 24 +-------- src/config.rs | 6 +++ src/gui.rs | 40 +++++++++++++-- src/learning.rs | 107 ++++++++++++++++++++++++++--------------- src/main.rs | 2 +- 6 files changed, 114 insertions(+), 68 deletions(-) diff --git a/config/config.json b/config/config.json index 4466886..d5d8d8e 100644 --- a/config/config.json +++ b/config/config.json @@ -6,5 +6,8 @@ "include_a": false, "learning_filepath": "./learning/learning.json", "max_learn_bin": 5, + "prefer_wrong": false, + "prefer_marked": false, + "prefer_new": false, "questions_filepath": "./questions/questions.json" } diff --git a/learning/learning.json b/learning/learning.json index 53f8750..9e26dfe 100644 --- a/learning/learning.json +++ b/learning/learning.json @@ -1,23 +1 @@ -{ - "BE413": { - "current_bin": 1 - }, - "NE207": { - "current_bin": 1 - }, - "BD205": { - "current_bin": 1 - }, - "VD733": { - "current_bin": 1 - }, - "VD716": { - "current_bin": 1 - }, - "NF109": { - "current_bin": 1 - }, - "VD731": { - "current_bin": 1 - } -} +{} \ No newline at end of file diff --git a/src/config.rs b/src/config.rs index c849bfe..6d966ed 100644 --- a/src/config.rs +++ b/src/config.rs @@ -11,6 +11,9 @@ pub struct Config { pub include_a: bool, pub learning_filepath: String, pub max_learn_bin: u64, + pub prefer_wrong: bool, + pub prefer_marked: bool, + pub prefer_new: bool, pub questions_filepath: String, } @@ -24,6 +27,9 @@ impl Config { include_a: false, learning_filepath: String::from("./learning/learning.json"), max_learn_bin: 5, + prefer_wrong: false, + prefer_marked: false, + prefer_new: false, questions_filepath: String::from("./questions/questions.json"), } } diff --git a/src/gui.rs b/src/gui.rs index eb2022a..d94d4f0 100644 --- a/src/gui.rs +++ b/src/gui.rs @@ -1,6 +1,6 @@ use crate::{ config::Config, - learning::{self, Answer, LearnState}, + learning::{self, save_learning, Answer, LearnState}, question, }; use eframe::{ @@ -22,7 +22,8 @@ pub fn run( // Application state let mut eligible_questions = question::get_eligible_questions(&questions, &config); - let mut print_question = learning::get_next_print_question(&eligible_questions, &learning); + let mut print_question = + learning::get_next_print_question(&eligible_questions, &mut learning, &config); let mut has_answered = false; let mut has_answered_first = false; let mut given_answer: usize = 0; @@ -85,6 +86,20 @@ pub fn run( } }); + ui.horizontal(|ui| { + ui.label("Nur anzuzeigen (wenn gegeben):"); + if ui.checkbox(&mut config.prefer_wrong, "Falsch beantwortete Fragen").changed() { + config.save(); + } + if ui.checkbox(&mut config.prefer_marked, "Markierte Fragen").changed() { + config.save(); + } + if ui.checkbox(&mut config.prefer_new, "Neue Fragen").changed() { + config.save(); + } + }); + + ui.separator(); if print_question.question.picture_question.len() > 0 { let pathstr = format!( "file://resources/fragenkatalog/svgs/{}.svg", @@ -106,7 +121,6 @@ pub fn run( } } - ui.separator(); ui.heading(&print_question.question.identifier); ui.label(&print_question.question.question); @@ -143,6 +157,19 @@ pub fn run( ui.label(print_question.get_shuffled_answer(index_name_tuple.0)); } + ui.separator(); + if learning.get(&print_question.question.identifier).unwrap().marked { + if ui.button("[X] Entmarkieren").clicked() { + learning.get_mut(&print_question.question.identifier).unwrap().marked = false; + } + learning::save_learning(&learning); + } else { + if ui.button("[ ] Markieren").clicked() { + learning.get_mut(&print_question.question.identifier).unwrap().marked = true; + } + learning::save_learning(&learning); + } + ui.separator(); if has_answered { if print_question.answer_shuffle[given_answer] == Answer::A { @@ -172,9 +199,14 @@ pub fn run( } if ui.button("Nächste Frage").clicked() { print_question = - learning::get_next_print_question(&eligible_questions, &learning); + learning::get_next_print_question(&eligible_questions, &mut learning, &config); has_answered = false; } + } else { + if ui.button("Überspringen").clicked() { + print_question = + learning::get_next_print_question(&eligible_questions, &mut learning, &config); + } } }); }); diff --git a/src/learning.rs b/src/learning.rs index fb42f9c..bbae0f0 100644 --- a/src/learning.rs +++ b/src/learning.rs @@ -1,3 +1,4 @@ +use crate::config::Config; use crate::question::Question; use crate::{config, helper}; use rand::seq::SliceRandom; @@ -9,6 +10,20 @@ use std::path::Path; #[derive(Serialize, Deserialize, Debug)] pub struct LearnState { pub current_bin: u64, + pub correct: u64, + pub wrong: u64, + pub marked: bool, +} + +impl LearnState { + pub fn new() -> LearnState { + LearnState { + current_bin: 0, + correct: 0, + wrong: 0, + marked: false, + } + } } pub fn handle_correct_answer( @@ -16,31 +31,22 @@ pub fn handle_correct_answer( identifier: &str, config: &config::Config, ) { - let current_bin = match learning.get(identifier) { - Some(learn_state) => learn_state.current_bin, - None => 1, - }; - if current_bin > config.max_learn_bin { - return; - } - learning + let learn_state = learning .entry(identifier.to_string()) - .or_insert(LearnState { current_bin: 0 }) - .current_bin += 1; + .or_insert(LearnState::new()); + learn_state.current_bin += 1; + if learn_state.current_bin > config.max_learn_bin { + learn_state.current_bin = config.max_learn_bin; + } + learn_state.correct += 1; } pub fn handle_wrong_answer(learning: &mut HashMap, identifier: &str) { - let current_bin = match learning.get(identifier) { - Some(learn_state) => learn_state.current_bin, - None => 2, - }; - if current_bin <= 1 { - return; - } - learning + let learn_state = learning .entry(identifier.to_string()) - .or_insert(LearnState { current_bin: 1 }) - .current_bin = 1; + .or_insert(LearnState::new()); + learn_state.current_bin = 1; + learn_state.wrong += 1; } pub fn load_learning() -> HashMap { @@ -62,7 +68,6 @@ pub fn load_learning() -> HashMap { pub fn save_learning(learn_state: &HashMap) { let json_string = serde_json::to_string_pretty(learn_state).unwrap(); - println!("C"); helper::overwrite_file_str("./learning/learning.json", &json_string); } @@ -113,26 +118,43 @@ impl PrintQuestion { pub fn get_next_print_question( eligible_questions: &Vec, - learning: &HashMap, + learning: &mut HashMap, + config: &Config, ) -> PrintQuestion { let mut rng: rand::prelude::ThreadRng = rand::thread_rng(); - let mut counter = rng.gen_range(0..eligible_questions.len() - 1); + let mut index = rng.gen_range(0..eligible_questions.len() - 1); + let mut counter = 0; + let mut ignore_preferences = false; loop { - let question = &eligible_questions[counter]; + let question = &eligible_questions[index]; let learn_state = learning - .get(&question.identifier) - .unwrap_or(&LearnState { current_bin: 1 }); - - let threshold = match learn_state.current_bin { - 1 => 5, - 2 => 40, - 3 => 70, - 4 => 80, - 5 => 85, - _ => 95, - }; - - if rng.gen_range(0..=100) > threshold { + .entry(String::from(&question.identifier)) + .or_insert(LearnState::new()); + + let mut is_eligible = false; + if !ignore_preferences { + let is_marked = (learn_state.marked) && config.prefer_marked; + let is_wrong = (learn_state.wrong > 0) && config.prefer_wrong; + let is_new = ((learn_state.wrong + learn_state.correct) == 0) && config.prefer_new; + if is_marked || is_wrong || is_new { + is_eligible = true; + } + } else { + let threshold = match learn_state.current_bin { + 1 => 5, + 2 => 40, + 3 => 70, + 4 => 80, + 5 => 85, + _ => 0, + }; + + if rng.gen_range(0..=100) > threshold { + is_eligible = true; + } + } + + if is_eligible { let mut answer_shuffle = vec![Answer::A, Answer::B, Answer::C, Answer::D]; answer_shuffle.shuffle(&mut rng); @@ -142,10 +164,15 @@ pub fn get_next_print_question( }; } - if counter >= eligible_questions.len() - 1 { - counter = 0; + if index >= eligible_questions.len() - 1 { + index = 0; } else { - counter += 1; + index += 1; + } + + counter += 1; + if counter >= eligible_questions.len() { + ignore_preferences = true; } } } diff --git a/src/main.rs b/src/main.rs index bc78d98..4412c6d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,5 +12,5 @@ fn main() { let questions_json_str = helper::read_filetext("./resources/ffh_questions.json"); let questions: Vec = serde_json::from_str(&questions_json_str).unwrap(); - gui::run(config, learning, questions); + gui::run(config, learning, questions).unwrap(); } From 12701fae8a2573ed2a576c676d40bd6bf232d795 Mon Sep 17 00:00:00 2001 From: Paulocracy <36934614+Paulocracy@users.noreply.github.com> Date: Sat, 3 Feb 2024 12:09:02 +0100 Subject: [PATCH 2/3] More statistics & Some code optimizations --- src/gui.rs | 4 ++-- src/helper.rs | 9 +++++++++ src/learning.rs | 23 +++++++++++------------ 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/src/gui.rs b/src/gui.rs index d94d4f0..dc81f48 100644 --- a/src/gui.rs +++ b/src/gui.rs @@ -162,12 +162,12 @@ pub fn run( if ui.button("[X] Entmarkieren").clicked() { learning.get_mut(&print_question.question.identifier).unwrap().marked = false; } - learning::save_learning(&learning); + save_learning(&learning); } else { if ui.button("[ ] Markieren").clicked() { learning.get_mut(&print_question.question.identifier).unwrap().marked = true; } - learning::save_learning(&learning); + save_learning(&learning); } ui.separator(); diff --git a/src/helper.rs b/src/helper.rs index 46adfce..da308c8 100644 --- a/src/helper.rs +++ b/src/helper.rs @@ -4,6 +4,7 @@ use rayon::prelude::*; use std::fs; use std::io::Write; use std::path::Path; +use std::time::{SystemTime, UNIX_EPOCH}; pub fn read_filelines(filename: &str) -> Vec { fs::read_to_string(filename) @@ -56,3 +57,11 @@ pub fn ensure_dir_existence(dir: &str) { } } } + +pub fn get_current_unixtime_in_sec() -> u64 { + let now = SystemTime::now(); + match now.duration_since(UNIX_EPOCH) { + Ok(n) => n.as_secs(), + Err(_) => 0, + } +} diff --git a/src/learning.rs b/src/learning.rs index bbae0f0..265d71f 100644 --- a/src/learning.rs +++ b/src/learning.rs @@ -13,6 +13,8 @@ pub struct LearnState { pub correct: u64, pub wrong: u64, pub marked: bool, + pub rounds_since_wrong: u64, + pub time_last_answer: u64, } impl LearnState { @@ -22,6 +24,8 @@ impl LearnState { correct: 0, wrong: 0, marked: false, + rounds_since_wrong: 0, + time_last_answer: 0, } } } @@ -39,6 +43,8 @@ pub fn handle_correct_answer( learn_state.current_bin = config.max_learn_bin; } learn_state.correct += 1; + learn_state.rounds_since_wrong += 1; + learn_state.time_last_answer = helper::get_current_unixtime_in_sec(); } pub fn handle_wrong_answer(learning: &mut HashMap, identifier: &str) { @@ -47,6 +53,8 @@ pub fn handle_wrong_answer(learning: &mut HashMap, identifie .or_insert(LearnState::new()); learn_state.current_bin = 1; learn_state.wrong += 1; + learn_state.rounds_since_wrong = 0; + learn_state.time_last_answer = helper::get_current_unixtime_in_sec(); } pub fn load_learning() -> HashMap { @@ -148,10 +156,7 @@ pub fn get_next_print_question( 5 => 85, _ => 0, }; - - if rng.gen_range(0..=100) > threshold { - is_eligible = true; - } + is_eligible = rng.gen_range(0..=100) > threshold; } if is_eligible { @@ -164,15 +169,9 @@ pub fn get_next_print_question( }; } - if index >= eligible_questions.len() - 1 { - index = 0; - } else { - index += 1; - } + index = (index + 1) % eligible_questions.len(); counter += 1; - if counter >= eligible_questions.len() { - ignore_preferences = true; - } + ignore_preferences = counter >= eligible_questions.len(); } } From 18e1af3c76c8bac0bc0fc1afd5ccc1e2d411fedf Mon Sep 17 00:00:00 2001 From: Paulocracy <36934614+Paulocracy@users.noreply.github.com> Date: Tue, 6 Feb 2024 19:31:13 +0100 Subject: [PATCH 3/3] More comments & Expanded README --- README.md | 24 ++- raw_json_to_ffh_json.py | 13 ++ resources/fragenkatalog/test.json | 16 -- screenshot.png | Bin 44208 -> 59155 bytes src/config.rs | 26 ++++ src/gui.rs | 98 ++++++++---- src/helper.rs | 84 ++++++---- src/learning.rs | 248 ++++++++++++++++++++++-------- src/main.rs | 14 +- src/question.rs | 31 ++++ 10 files changed, 403 insertions(+), 151 deletions(-) delete mode 100644 resources/fragenkatalog/test.json diff --git a/README.md b/README.md index fb83470..644d6d4 100644 --- a/README.md +++ b/README.md @@ -2,32 +2,40 @@ -Dieses kleine Programm kann eine Unterstützung beim Lernen für die deutsche Amateurfunkprüfung der Klassen N, E und/oder A sein. Hierbei werden Fragen, die man falsch beantwortet hat, mit einer erhöhten Wahrscheinlichkeit wieder abgefragt im Vergleich zu den Fragen, die man schon häufiger richtig beantwortet hat. +Dieses kleine Programm kann einem beim Lernen für die deutsche Amateurfunkprüfung der Klassen N, E und/oder A helfen. Die gestellten Fragen entstammen aus dem offizielle Fragenkatalog der Bundesnetzagentur (siehe auch Abschnitt [Lizenzen](#lizenzen)). Hierbei kann man sich auf Fragen der Kategorien V (Vorschriften), B (Betriebliches), N (Technik Klasse N), E (Technik Klasse E) und/oder A (Technik Klasse A) konzentrieren. -Programmatisch ist der Funkfragenhelfer in Rust geschrieben, außer einem kleinen Pythonskript, welches den ursprünglichen Fragenkatalog in ein für den Funkfragenhelfer leichter lesbares Format umwandelt, und nutzt die Bibliotheken eframe, egui und egui-extras für die graphische Benutzeroberfläche, rayon für ein wenig Parallelisierung und serde bzw. serde-json für die (De)serialisierung von JSON-Dateien. Dies ist eines meiner ersten in Rust verfassten Programme, daher gibt es im Code wahrscheinlich ein großes Verbesserungspotential. Erweiterte Kommentare folgen in späteren Versionen. +Um den Lernfortschritt zu unterstützen, bietet der Funkfragenhelfer die Möglichkeit, die gestellten Fragen zu filtern, dabei lassen sich folgende Filterinstellungen frei kombinieren (falls solche Kombinationen bestehen): -Wer einen kompletten Lehrgang für die Amateurfunkprüfung, und alternative Apps mit mehr Funktionen und mehr unterstützten Systemen, für die Amateurfunkprüfung sucht, dem empfehle ich [50Ω](https://50ohm.de/) aus den Reihen des Deutschen Amateur-Radio-Clubs (DARC). Der hiesige kleine Funkfragenhelfer steht in keiner Verbindung mit 50Ω. +* Von einem markierte Fragen (dies bietet sich bspw. für schwere Fragen an) +* Fragen, die man mindestens einmal falsch beantwortet hat +* Fragen, die man noch nicht beantwortet hat + +Mit aktiven Filtern, falls Fragen die zu den Filtern passen existieren, wird eine zufällige passende Frage aus den ausgewählten Fragekategorien gestellt. Ohne aktive Filter, oder wenn keine Frage zu den aktiven Filtern passen, werden alle Fragen der ausgewählten Fragekategorien, die man falsch beantwortet hat, mit einer erhöhten Wahrscheinlichkeit wieder abgefragt im Vergleich zu den Fragen, die man schon häufiger richtig beantwortet hat. + +Programmatisch ist der Funkfragenhelfer in Rust geschrieben (außer einem kleinen, für das Starten des Funkfragenhelfers nicht notwendiges, Pythonskript, welches den ursprünglichen Fragenkatalog in ein für den Funkfragenhelfer leichter lesbares Format umwandelt), und nutzt die Bibliotheken [egui](https://github.com/emilk/egui), [eframe](https://docs.rs/eframe/latest/eframe/) sowie [egui-extras](https://docs.rs/egui_extras/latest/egui_extras/) für die graphische Benutzeroberfläche, [rayon](https://github.com/rayon-rs/rayon) für ein wenig Parallelisierung und [serde](https://github.com/serde-rs/serde) bzw. [serde_json](https://docs.rs/serde_json/latest/serde_json/) für die (De)serialisierung von JSON-Dateien. Dies ist eines meiner ersten in Rust verfassten Programme, daher gibt es im Code wahrscheinlich große Verbesserungspotentiale. + +Wer einen kompletten Lehrgang für die Amateurfunkprüfung, und alternative Apps mit mehr Funktionen und mehr unterstützten Systemen, für die Amateurfunkprüfung sucht, dem empfehle ich [50Ω](https://50ohm.de/) aus den Reihen des Deutschen Amateur-Radio-Clubs (DARC). Der hiesige kleine Funkfragenhelfer steht in keiner Verbindung zu 50Ω. ## Installation Unter Windows ist der einfachste Weg, die .zip-Datei "Funkfragenhelfer_Windows.zip" [im letzten Release](https://github.com/Paulocracy/Funkfragenhelfer/releases/latest) unter "Assets" herunterzuladen, an einem beliebigen Ort zu entpacken und dann im entpackten Ordner "Funkfragenhelfer" die "funkfragenhelfer.exe" auszuführen. -Unter anderen, vom Autor bislang nicht getesteten, Systemen (wie Linux und MacOS) empfiehlt sich die Nutzung von Git und cargo, hierfür kloniert man zunächst das Repository: +Unter anderen, vom Autor bislang nicht getesteten, Systemen (wie Linux und MacOS) empfiehlt sich die Nutzung von Git und cargo, hierfür kann man z.B. im Terminal zunächst das Repository clonen per ```sh git clone https://github.com/Paulocracy/Funkfragenhelfer ``` -...und kompiliert und führt das Programm mit Cargo aus: +und kompiliert und führt das Programm dann mit Cargo aus: ```sh -cd Funkfragenhelfer # Falls man noch nicht im neu erstellten Ordner ist +cd Funkfragenhelfer # Falls man noch nicht im von Git neu erstellten Ordner ist cargo run ``` ## Lizenzen Als Quelle für die hier genutzten Fragen dient der von der von der Bundesnetzagentur für Elektrizität, Gas, -Telekommunikation, Post und Eisenbahnen bereitgestellte Datensatz "Prüfungsfragen zum Erwerb von Amateurfunkprüfungsbescheinigungen, 2. Auflage, Dezember 2023", der über [[diesen Link (Stand: Januar 2024)]](https://www.bundesnetzagentur.de/SharedDocs/Downloads/DE/Sachgebiete/Telekommunikation/Unternehmen_Institutionen/Frequenzen/Amateurfunk/Fragenkatalog/PruefungsfragenZIP.zip) bezogen wurde und unter den Bedingungen der ["Datenlizenz Deutschland – Namensnennung – Version 2.0"](https://www.govdata.de/dl-de/by-2-0) lizenziert ist. Der Datensatz selber ist in diesem Repository im Unterordner "resources/fragenkatalog" auffindbar. +Telekommunikation, Post und Eisenbahnen bereitgestellte Datensatz "Prüfungsfragen zum Erwerb von Amateurfunkprüfungsbescheinigungen, 2. Auflage, Dezember 2023", der über [diesen Link (Stand: Januar 2024)](https://www.bundesnetzagentur.de/SharedDocs/Downloads/DE/Sachgebiete/Telekommunikation/Unternehmen_Institutionen/Frequenzen/Amateurfunk/Fragenkatalog/PruefungsfragenZIP.zip) bezogen wurde und unter den Bedingungen der ["Datenlizenz Deutschland – Namensnennung – Version 2.0"](https://www.govdata.de/dl-de/by-2-0) lizenziert ist. Der Datensatz selber ist in diesem Repository im Unterordner "resources/fragenkatalog" auffindbar. -Das Programm selber, ohne den Prüfungskatalog, ist unter der Apache-Lizenz 2.0 lizensiert, welche in der Datei LICENSE abgerufen werden kann. +Der Funkfragenhelfer selber, ohne den Prüfungskatalog, ist unter der Apache-Lizenz 2.0 lizensiert, welche in der Datei [LICENSE](./LICENSE) abgerufen werden kann. diff --git a/raw_json_to_ffh_json.py b/raw_json_to_ffh_json.py index a094359..f703e61 100644 --- a/raw_json_to_ffh_json.py +++ b/raw_json_to_ffh_json.py @@ -1,3 +1,16 @@ +""" +This little script converts the Bundesnetzegentur JSON with the +amateur radio questions into an easier format (easier for the +Funkfragenhelfer) without sections and titles. Just compare +"resources/fragenkatalog/fragenkatalog.json" to +"resources/ffh_questions.json" to see the difference. + +This script has no special dependencies and should run with any +newer Python 3 interpreter (new as of 2024). It was tested with +Python 3.9, but can probably run with any newer version, and +maybe even older versions, too. +""" + import json from typing import Any diff --git a/resources/fragenkatalog/test.json b/resources/fragenkatalog/test.json deleted file mode 100644 index e35adbe..0000000 --- a/resources/fragenkatalog/test.json +++ /dev/null @@ -1,16 +0,0 @@ -[ - { - "category": "A", - "identifier": "AB407", - "question": "Welches Signal passt zu folgendem Frequenzspektrum?", - "answer_a": "", - "answer_b": "", - "answer_c": "", - "answer_d": "", - "picture_question": "AB407_q", - "picture_a": "AB407_a", - "picture_b": "AB407_b", - "picture_c": "AB407_c", - "picture_d": "AB407_d" - }, -] \ No newline at end of file diff --git a/screenshot.png b/screenshot.png index b4fc9e3affba4a57b46c475ec1dc4e11f461aad9..6312c42bb1580dfcf6056c91fae443c45c947eb3 100644 GIT binary patch literal 59155 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⪼+T4j0rpxmbkw{jb;T#2pa}wnyT{QSK$v%TZ7C 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 Config { Config { include_v: true, @@ -34,11 +53,15 @@ impl Config { } } + /// Save the config in the config.json (the directory's existence + /// was ensured beforehand with this module's load_config()). pub fn save(&self) { let json_str = serde_json::to_string_pretty(&self).unwrap(); helper::overwrite_file_str("./config/config.json", &json_str); } + /// Returns whether or not all categories were set off (used by the GUI to prevent that + /// a user shuts off all questions). pub fn all_includes_false(&self) -> bool { return !self.include_a && !self.include_b @@ -48,6 +71,9 @@ impl Config { } } +// PUBLIC FUNCTION SECTION // +/// Loads the config.json Config, or, if it doesn't exist, creates +/// a new such JSON with default values. pub fn load_config() -> Config { let config_dir_path = Path::new("./config"); if !config_dir_path.exists() { diff --git a/src/gui.rs b/src/gui.rs index dc81f48..ab55b6b 100644 --- a/src/gui.rs +++ b/src/gui.rs @@ -1,54 +1,80 @@ +//! This module defines the full Funkfragenhelfer GUI using egui and eframe. +//! Note that egui uses an "immediate mode" GUI concept, which means +//! that the GUI is written in each frame, so that the behavior of GUI +//! elements is written together with their action behavior (i.e., +//! GUI elements are declared and act right in the run loop). +//! +//! If you wish to change Frunkfragenhelfer's GUI framework, you just +//! have to edit this file as the other modules are GUI-framework-agnostic. + +// IMPORTS SECTION // use crate::{ config::Config, - learning::{self, save_learning, Answer, LearnState}, + learning::{self, save_learning, Answer, LearnStates}, question, }; use eframe::{ egui::{self, FontId, RichText, Vec2}, epaint::Color32, }; -use std::collections::HashMap; use std::path::Path; +// CONSTANTS SECTION // +/// Maximal image width for the GUI display +const MAX_IMAGE_WIDTH: f32 = 250.0; +/// Maximal image height for the GUI display +const MAX_IMAGE_HEIGHT: f32 = 250.0; + +/// Runs the Funkfragenhelfer GUI +/// +/// Here, the full GUI and all its actions are defined. +/// +/// ### Arguments +/// * config: The current Funkfragenhelfer configuration +/// * learn_states: The current question LearnStates +/// * questions: The set of all questions that can be asked pub fn run( mut config: Config, - mut learning: HashMap, + mut learn_states: LearnStates, questions: Vec, ) -> Result<(), eframe::Error> { + // Set the egui options let options = eframe::NativeOptions { viewport: egui::ViewportBuilder::default().with_inner_size([800.0, 1000.0]), ..Default::default() }; // Application state - let mut eligible_questions = question::get_eligible_questions(&questions, &config); - let mut print_question = - learning::get_next_print_question(&eligible_questions, &mut learning, &config); let mut has_answered = false; let mut has_answered_first = false; + let mut eligible_questions = question::get_eligible_questions(&questions, &config); let mut given_answer: usize = 0; - let mut answer_text = String::from(""); - - const IMAGE_WIDTH: f32 = 250.0; - const IMAGE_HEIGHT: f32 = 250.0; + let mut print_question = + learning::get_next_print_question(&eligible_questions, &mut learn_states, &config); let index_name_tuples = vec![(0, "A"), (1, "B"), (2, "C"), (3, "D")]; - // GUI routines + // GUI main run loop; We use "run_simple_native" as the simplest + // egui wrapper available. eframe::run_simple_native("Funkfragenhelfer V 0.1", options, move |ctx, _frame| { + // Image loader do teh question images; Can also load SVGs egui_extras::install_image_loaders(ctx); + // Central widget which includes all other widhets egui::CentralPanel::default().show(ctx, |ui| { egui::ScrollArea::both().show(ui, |ui| { - answer_text = String::from("Bild"); + let mut answer_text = String::from("Bild"); + // Show question data source ui.label(RichText::new("Bereitsteller der Fragen: Bundesnetzagentur, \ - Datensatz: 'Prüfungsfragen zum Erwerb von Amateurfunkprüfungsbescheinigungen, \ + Datensatz: 'Prüfungsfragen zum \ + Erwerb von Amateurfunkprüfungsbescheinigungen, \ 2. Auflage, Dezember 2023', Lizenz der Fragen: dl-de/by-2-0" ).font(FontId::proportional(10.0)).color(Color32::DARK_GRAY)); + // Show and handle question categories ui.horizontal(|ui| { - ui.label("Frageklassen:"); + ui.label("Fragekategorien:"); if ui.checkbox(&mut config.include_v, "V").changed() { if config.all_includes_false() { config.include_v = true; @@ -86,19 +112,23 @@ pub fn run( } }); + // Show and handle question filters ui.horizontal(|ui| { - ui.label("Nur anzuzeigen (wenn gegeben):"); - if ui.checkbox(&mut config.prefer_wrong, "Falsch beantwortete Fragen").changed() { + ui.label("Filter (falls anwendbar):"); + if ui.checkbox(&mut config.prefer_marked, "Markierte Fragen").changed() { config.save(); } - if ui.checkbox(&mut config.prefer_marked, "Markierte Fragen").changed() { + if ui.checkbox(&mut config.prefer_wrong, "Falsch beantwortete Fragen").changed() { config.save(); } - if ui.checkbox(&mut config.prefer_new, "Neue Fragen").changed() { + if ui.checkbox(&mut config.prefer_new, "Noch nicht beantwortete Fragen").changed() { config.save(); } }); + // Show picture question if one exists. Here, it is also made sure that such + // a picture really exists as there seem to be some wrong picture associations + // in the Bundesnetzagentur dataset. ui.separator(); if print_question.question.picture_question.len() > 0 { let pathstr = format!( @@ -114,16 +144,19 @@ pub fn run( if path.exists() { ui.add( egui::Image::new(pathstr) - .fit_to_exact_size(Vec2::new(IMAGE_WIDTH, IMAGE_HEIGHT)) + .fit_to_exact_size(Vec2::new(MAX_IMAGE_WIDTH, MAX_IMAGE_HEIGHT)) .maintain_aspect_ratio(true) .bg_fill(Color32::DARK_GRAY), ); } } + // Print the current question's identifier and the question itself + // (without answers yet). ui.heading(&print_question.question.identifier); ui.label(&print_question.question.question); + // Show picture answers (if they exist) if print_question.question.picture_a.len() > 0 { ui.separator(); @@ -135,7 +168,7 @@ pub fn run( "file://resources/fragenkatalog/svgs/{}.svg", print_question.get_shuffled_picture(index_name_tuple.0) )) - .fit_to_exact_size(Vec2::new(IMAGE_WIDTH, IMAGE_HEIGHT)) + .fit_to_exact_size(Vec2::new(MAX_IMAGE_WIDTH, MAX_IMAGE_HEIGHT)) .maintain_aspect_ratio(true) .bg_fill(Color32::DARK_GRAY), ); @@ -145,6 +178,7 @@ pub fn run( answer_text = String::from("Antwort"); } + // Handle answer printing (if an answer has no text, "" is displayed) for &index_name_tuple in &index_name_tuples { ui.separator(); if ui.button(format!("{} {}", answer_text, index_name_tuple.1)).clicked() { @@ -157,30 +191,32 @@ pub fn run( ui.label(print_question.get_shuffled_answer(index_name_tuple.0)); } + // Handling of question marking ui.separator(); - if learning.get(&print_question.question.identifier).unwrap().marked { + if learn_states.get(&print_question.question.identifier).unwrap().marked { if ui.button("[X] Entmarkieren").clicked() { - learning.get_mut(&print_question.question.identifier).unwrap().marked = false; + learn_states.get_mut(&print_question.question.identifier).unwrap().marked = false; } - save_learning(&learning); + save_learning(&learn_states); } else { if ui.button("[ ] Markieren").clicked() { - learning.get_mut(&print_question.question.identifier).unwrap().marked = true; + learn_states.get_mut(&print_question.question.identifier).unwrap().marked = true; } - save_learning(&learning); + save_learning(&learn_states); } + // Handling of the case that the user answered the question ui.separator(); if has_answered { if print_question.answer_shuffle[given_answer] == Answer::A { ui.label("Korrekt!"); if has_answered_first { learning::handle_correct_answer( - &mut learning, + &mut learn_states, &print_question.question.identifier, &config, ); - learning::save_learning(&learning); + learning::save_learning(&learn_states); has_answered_first = false; } } else { @@ -190,22 +226,22 @@ pub fn run( )); if has_answered_first { learning::handle_wrong_answer( - &mut learning, + &mut learn_states, &print_question.question.identifier, ); - learning::save_learning(&learning); + learning::save_learning(&learn_states); has_answered_first = false; } } if ui.button("Nächste Frage").clicked() { print_question = - learning::get_next_print_question(&eligible_questions, &mut learning, &config); + learning::get_next_print_question(&eligible_questions, &mut learn_states, &config); has_answered = false; } } else { if ui.button("Überspringen").clicked() { print_question = - learning::get_next_print_question(&eligible_questions, &mut learning, &config); + learning::get_next_print_question(&eligible_questions, &mut learn_states, &config); } } }); diff --git a/src/helper.rs b/src/helper.rs index da308c8..f5e828c 100644 --- a/src/helper.rs +++ b/src/helper.rs @@ -1,24 +1,50 @@ +//! This module contains small but possibly useful +//! Rust utility functions, currently focused on +//! file I/O and time. + +// MACRO DIRECTIVES SECTION // #![allow(dead_code)] +// IMPORTS SECTION // use rayon::prelude::*; use std::fs; use std::io::Write; use std::path::Path; use std::time::{SystemTime, UNIX_EPOCH}; -pub fn read_filelines(filename: &str) -> Vec { - fs::read_to_string(filename) - .unwrap() - .par_lines() - .map(String::from) - .collect() +// PUBLIC FUNCTIONS SECTION // +/// Ensure the existence of the given directory. +/// +/// If the directory exists, nothing is done. If it +/// does not exist, a new directory is created. If an +/// error occurs during the directory creation, the +/// error will be printed. +pub fn ensure_dir_existence(dir: &str) { + let path = Path::new(dir); + if path.exists() && path.is_dir() { + return; + } + match fs::create_dir_all(path) { + Ok(_) => {} + Err(e) => { + println!("Error in creating {}: {}", dir, e) + } + } } -pub fn read_filetext(filename: &str) -> String { - let filelines = read_filelines(filename); - filelines.join(" ") +/// Returns the number of seconds since the UNIX epoch as u64. +pub fn get_current_unixtime_in_sec() -> u64 { + let now = SystemTime::now(); + match now.duration_since(UNIX_EPOCH) { + Ok(n) => n.as_secs(), + Err(_) => 0, + } } +/// Returns the filenames in the given directory +/// +/// You must make sure beforehand that the directory exists. Otherwise, +/// the function panics. pub fn get_filenames_in_dir(dir: &str) -> Vec { let path = Path::new(dir); let filenames: Vec = fs::read_dir(path) @@ -26,15 +52,21 @@ pub fn get_filenames_in_dir(dir: &str) -> Vec { .par_bridge() .map(|path| path.unwrap().path()) .filter(|path| path.is_file()) - .map(|path| path.to_str().unwrap().to_owned().replace("\\", "")) + .map(|path| path.to_str().unwrap().to_owned().replace("\\", "/")) .collect(); filenames } -pub fn overwrite_file_str(filepath: &str, text: &str) { - let path = Path::new(filepath); - let mut f = fs::File::create(path).unwrap(); - writeln!(f, "{}", text).unwrap(); +/// Returns all lines of the given file as Vec. +/// +/// Make sure that the file exists beforehand. Otherwise, +/// this function panics. +pub fn read_filelines(filename: &str) -> Vec { + fs::read_to_string(filename) + .unwrap() + .par_lines() + .map(String::from) + .collect() } pub fn overwrite_file_lines(filepath: &str, lines: Vec) { @@ -45,23 +77,13 @@ pub fn overwrite_file_lines(filepath: &str, lines: Vec) { } } -pub fn ensure_dir_existence(dir: &str) { - let path = Path::new(dir); - if path.exists() && path.is_dir() { - return; - } - match fs::create_dir_all(path) { - Ok(_) => {} - Err(e) => { - println!("Error in creating {}: {}", dir, e) - } - } +pub fn overwrite_file_str(filepath: &str, text: &str) { + let path = Path::new(filepath); + let mut f = fs::File::create(path).unwrap(); + writeln!(f, "{}", text).unwrap(); } -pub fn get_current_unixtime_in_sec() -> u64 { - let now = SystemTime::now(); - match now.duration_since(UNIX_EPOCH) { - Ok(n) => n.as_secs(), - Err(_) => 0, - } +pub fn read_filetext(filename: &str) -> String { + let filelines = read_filelines(filename); + filelines.join(" ") } diff --git a/src/learning.rs b/src/learning.rs index 265d71f..f5dd86a 100644 --- a/src/learning.rs +++ b/src/learning.rs @@ -1,3 +1,8 @@ +//! In this module, the structs and functions for the learning +//! algorithm can be found. See the comment of the "LearnState" +//! and "PrintQuestion" structs for more. + +// IMPORTS SECTION // use crate::config::Config; use crate::question::Question; use crate::{config, helper}; @@ -7,17 +12,47 @@ use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::path::Path; +// ENUMS SECTION // +/// Represents the possible answers A to B. +#[derive(PartialEq, Debug)] +pub enum Answer { + A, + B, + C, + D, +} + +// STRUCTS SECTION // +/// Represents the learning progress or "state" of a question. +/// +/// Each question can have its own `LearnState` instance, which +/// describes, e.g., how many times the question was answered +/// correctly or wrongly. In addition, it contains the learning +/// "bin", which has a minimal value of 1 and a maximum of 5. Each +/// time the user answers a question corrcectly, the bin rises by 1 (or +/// stays at the maximum). Is the answer wrong, a question's bin is +/// set to 1 again. Now, the higher the bin, the lower the probability +/// is that the question is asked. #[derive(Serialize, Deserialize, Debug)] pub struct LearnState { + /// The current learning "bin" pub current_bin: u64, + /// Number of correct answers up to now pub correct: u64, + /// Number of wrong answers up to now pub wrong: u64, + /// Whether or not the user marked the question pub marked: bool, + /// Number of times the question was asked since the user + /// gave a wrong answer pub rounds_since_wrong: u64, + /// The UNIX time when this question was last answered pub time_last_answer: u64, } impl LearnState { + /// Creates a new `LearnState` with default values, + /// as if this question was never asked. pub fn new() -> LearnState { LearnState { current_bin: 0, @@ -30,34 +65,117 @@ impl LearnState { } } +/// Type alias for the full collection of LearnState instances. +pub type LearnStates = HashMap; + +/// Representation of a print-friendly question. +/// +/// In contrast to a normal Question, which is included here too, +/// this struct also constaint an "answer shuffle" which is a randomly +/// shuffled vector of the Answer instances. By following this vector, +/// a user interface can determine the random order of shown answers. +pub struct PrintQuestion { + pub question: Question, + pub answer_shuffle: Vec, +} + +impl PrintQuestion { + /// Looks where the "real" answer A is in the randomly shuffled answers + /// and returns its current Answer value. A is looked up as in + /// the questions database of the Bundesnetzagentur, A is always + /// the correct answer. + pub fn get_correct_answer(&self) -> Answer { + if self.answer_shuffle[0] == Answer::A { + Answer::A + } else if self.answer_shuffle[1] == Answer::A { + Answer::B + } else if self.answer_shuffle[2] == Answer::A { + Answer::C + } else { + Answer::D + } + } + + /// Returns the question string for the given randomly shuffled answer. + pub fn get_shuffled_answer(&self, index: usize) -> String { + match self.answer_shuffle[index] { + Answer::A => String::from(&self.question.answer_a), + Answer::B => String::from(&self.question.answer_b), + Answer::C => String::from(&self.question.answer_c), + Answer::D => String::from(&self.question.answer_d), + } + } + + pub fn get_shuffled_picture(&self, index: usize) -> String { + match self.answer_shuffle[index] { + Answer::A => String::from(&self.question.picture_a), + Answer::B => String::from(&self.question.picture_b), + Answer::C => String::from(&self.question.picture_c), + Answer::D => String::from(&self.question.picture_d), + } + } +} + +// PUBLIC FUNCTIONS SECTION // +/// Updates the LearnState of the given question for the case that +/// it was answered correctly. +/// +/// ### Arguments +/// * learning: All current LearnStates +/// * identifier: The correctly answered question's identifier (i.e., th +/// LearnStates key). +/// * config: The current Funkfragenhelfer configurarion; Determined the +/// maximal bin. pub fn handle_correct_answer( - learning: &mut HashMap, + learning: &mut LearnStates, identifier: &str, config: &config::Config, ) { + // Get the LearnState of the question (or create one + // if it doesn't exist yet) let learn_state = learning .entry(identifier.to_string()) .or_insert(LearnState::new()); - learn_state.current_bin += 1; - if learn_state.current_bin > config.max_learn_bin { - learn_state.current_bin = config.max_learn_bin; + // Set the bin 1 higher (or keep it at the maximum) + if learn_state.current_bin < config.max_learn_bin { + learn_state.current_bin += 1; } + // Update the rest of the LearnState statistics learn_state.correct += 1; learn_state.rounds_since_wrong += 1; learn_state.time_last_answer = helper::get_current_unixtime_in_sec(); } -pub fn handle_wrong_answer(learning: &mut HashMap, identifier: &str) { +/// Updates the LearnState of the given question for the case that +/// it was answered wrongly. +/// +/// ### Arguments +/// * learning: All current LearnStates +/// * identifier: The correctly answered question's identifier (i.e., th +/// LearnStates key). +pub fn handle_wrong_answer(learning: &mut LearnStates, identifier: &str) { + // Get the LearnState of the question (or create one + // if it doesn't exist yet) let learn_state = learning .entry(identifier.to_string()) .or_insert(LearnState::new()); + // Set the bin to 1 learn_state.current_bin = 1; + // Update the rest of the LearnState statistics learn_state.wrong += 1; learn_state.rounds_since_wrong = 0; learn_state.time_last_answer = helper::get_current_unixtime_in_sec(); } -pub fn load_learning() -> HashMap { +/// Loads the ./learninglearning.json file, or creates one if it doesn't exist. +/// +/// This file contains a LearnStates JSON representation and represents the full information +/// of each question's current learning progress. +/// +/// ### Return value +/// * The LearnStates, i.e. HashMap, of each question (with the +/// question identifiers as keys and the associated LearnState instances as values) +pub fn load_learning() -> LearnStates { let config_dir_path = Path::new("./learning"); if !config_dir_path.exists() { helper::ensure_dir_existence("./learning"); @@ -65,7 +183,7 @@ pub fn load_learning() -> HashMap { let config_file_path = Path::new("./learning/learning.json"); if !config_file_path.exists() { - let default_learning: HashMap = HashMap::new(); + let default_learning: LearnStates = HashMap::new(); let learning_json = serde_json::to_string_pretty(&default_learning).unwrap(); helper::overwrite_file_str("./learning/learning.json", &learning_json); } @@ -74,80 +192,80 @@ pub fn load_learning() -> HashMap { serde_json::from_str(&learning_text).unwrap() } -pub fn save_learning(learn_state: &HashMap) { - let json_string = serde_json::to_string_pretty(learn_state).unwrap(); +/// Saves the current LearnStates into the ./learning/learning.json +/// +/// The JSON file is going to be overwritten in the process. That the "learning" dir +/// exists is ensured through this module's load_learning() beforehand. +/// +/// ### Arguments +/// * learn_states: The current LearnStates for each question +pub fn save_learning(learn_states: &LearnStates) { + let json_string = serde_json::to_string_pretty(learn_states).unwrap(); helper::overwrite_file_str("./learning/learning.json", &json_string); } -#[derive(PartialEq, Debug)] -pub enum Answer { - A, - B, - C, - D, -} - -pub struct PrintQuestion { - pub question: Question, - pub answer_shuffle: Vec, -} - -impl PrintQuestion { - pub fn get_correct_answer(&self) -> Answer { - if self.answer_shuffle[0] == Answer::A { - Answer::A - } else if self.answer_shuffle[1] == Answer::A { - Answer::B - } else if self.answer_shuffle[2] == Answer::A { - Answer::C - } else { - Answer::D - } - } - - pub fn get_shuffled_answer(&self, index: usize) -> String { - match self.answer_shuffle[index] { - Answer::A => String::from(&self.question.answer_a), - Answer::B => String::from(&self.question.answer_b), - Answer::C => String::from(&self.question.answer_c), - Answer::D => String::from(&self.question.answer_d), - } - } - - pub fn get_shuffled_picture(&self, index: usize) -> String { - match self.answer_shuffle[index] { - Answer::A => String::from(&self.question.picture_a), - Answer::B => String::from(&self.question.picture_b), - Answer::C => String::from(&self.question.picture_c), - Answer::D => String::from(&self.question.picture_d), - } - } -} - +/// Out of the selected question categories and according to filters, select next question. +/// +/// This function essentially implements the simple learning algorithm used by +/// Funkfragenhelfer; Out of the eligible questions (i.e., the ones which are a +/// member of the selected categories), the following is done: +/// +/// 1. Start with a randomly chosen index for the list of eligible questions +/// 2. If filters are active: If the question at the current index fits to the +/// filters, return this question. If not, raise the index by 1 (or set to 0 +/// if greater than the list length) until a filter-fitting question appears +/// and can be returned. If no question fits to the filters, proceed with step +/// 3. +/// 3. Without filters: Look at the question at the current index. The higher its +/// bin, the lower the probability is chosen. If chosen, return the question. +/// If not chosen, proceed with the next question. This is repeated until a +/// question is chosen. +/// +/// ### Arguments +/// * eligible_questions: The list of category-fitting questions from which one is chosen. +/// * learning: The current LearnStates, providing, e.g., the question bins. +/// * config: The current Funkfragenhelfer Config. +/// +/// ### Return value +/// * A PrintQuestion, which includes the chosen question as well as randomly shuffled answers +/// (as in the original Bundesnetzagentur questions set, answer A is always correct). pub fn get_next_print_question( eligible_questions: &Vec, - learning: &mut HashMap, + learning: &mut LearnStates, config: &Config, ) -> PrintQuestion { + // Setup randomness let mut rng: rand::prelude::ThreadRng = rand::thread_rng(); + // Question-choosing state variables + // The current randomly initialized questions index let mut index = rng.gen_range(0..eligible_questions.len() - 1); + // A counter counting how many questions were already looked up let mut counter = 0; - let mut ignore_preferences = false; + // Start the question-choosing loop, which runs the algorithm as described + // in this method's description. loop { + // Get (or create if non-existent) the current LearnState let question = &eligible_questions[index]; let learn_state = learning .entry(String::from(&question.identifier)) .or_insert(LearnState::new()); - let mut is_eligible = false; - if !ignore_preferences { + // Variable choosing whether or not a question is chosen for the return value + let mut is_chosen = false; + // If we didn't already look at all questions... + if !(counter >= eligible_questions.len()) { + // ...look up if any filters apply to the current question... let is_marked = (learn_state.marked) && config.prefer_marked; let is_wrong = (learn_state.wrong > 0) && config.prefer_wrong; let is_new = ((learn_state.wrong + learn_state.correct) == 0) && config.prefer_new; + // ...if yes: Choose it if is_marked || is_wrong || is_new { - is_eligible = true; + is_chosen = true; } } else { + // If no question applies to filters, look at its bin and get the + // associated choosing probability (the higher the bin, the lower + // probability) let threshold = match learn_state.current_bin { 1 => 5, 2 => 40, @@ -156,22 +274,26 @@ pub fn get_next_print_question( 5 => 85, _ => 0, }; - is_eligible = rng.gen_range(0..=100) > threshold; + // If the threshold is *lower* than a random value, choose the question + is_chosen = rng.gen_range(0..=100) > threshold; } - if is_eligible { + // If a question is chosen as return value... + if is_chosen { + // ...shuffle its answers randomly... let mut answer_shuffle = vec![Answer::A, Answer::B, Answer::C, Answer::D]; answer_shuffle.shuffle(&mut rng); + // ...and return the shuffle result together with the Question return PrintQuestion { question: question.clone(), answer_shuffle, }; } + // Raise the index or set to 0 if it is greater than the eligible questions length index = (index + 1) % eligible_questions.len(); - + // Raise as we just looked at one more question counter += 1; - ignore_preferences = counter >= eligible_questions.len(); } } diff --git a/src/main.rs b/src/main.rs index 4412c6d..87ac612 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,16 +1,26 @@ +//! Main file of Funkfragenhelfer. +//! +//! Here, all Funkfragenhelfer modules are loaded and the GUI is started. +//! For more about the specific modules, look up their comments. Note that +//! only the "GUI" module contains egui code, all other modules are GUI-framework +//! agnostic. + +// Make sure that no console occurs under Windows in the release build #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] +// Load Funkfragenhelfer modules mod config; mod gui; mod helper; mod learning; mod question; +// Start Funkfragenhelger fn main() { let config = config::load_config(); - let learning = learning::load_learning(); + let learn_states: learning::LearnStates = learning::load_learning(); let questions_json_str = helper::read_filetext("./resources/ffh_questions.json"); let questions: Vec = serde_json::from_str(&questions_json_str).unwrap(); - gui::run(config, learning, questions).unwrap(); + gui::run(config, learn_states, questions).unwrap(); } diff --git a/src/question.rs b/src/question.rs index 56eafde..856c310 100644 --- a/src/question.rs +++ b/src/question.rs @@ -1,6 +1,18 @@ +//! This module includes the representation of questions +//! themselves, as well as the function for getting all +//! questions that are members of the chosen category. + +// IMPORTS SECTION // use crate::config::Config; use serde::{Deserialize, Serialize}; +// ENUM SECTION // +/// Representation of main questions categories, i.e.: +/// * V - Vorschriften +/// * B - Betriebliches +/// * N - Technik Klasse N +/// * E - Technik Klasse E +/// * A - Technik Klasse A #[derive(Clone, Serialize, Deserialize, Debug)] pub enum Category { V, @@ -10,24 +22,43 @@ pub enum Category { A, } +// STRUCT SECTION // +/// Representation of the full data for a question, including +/// its question category, question and answer texts. #[derive(Clone, Serialize, Deserialize, Debug)] pub struct Question { + /// The question's main category pub category: Category, + /// The question's identifier or "number" pub identifier: String, + /// The actual question text pub question: String, + /// Text of answer A (if existent, otherwise "") pub answer_a: String, + /// Text of answer B (if existent, otherwise "") pub answer_b: String, + /// Text of answer C (if existent, otherwise "") pub answer_c: String, + /// Text of answer D (if existent, otherwise "") pub answer_d: String, + /// Text of picture question (if existent, otherwise "") pub picture_question: String, + /// Text of picture answer A (if existent, otherwise "") pub picture_a: String, + /// Text of picture answer B (if existent, otherwise "") pub picture_b: String, + /// Text of picture answer C (if existent, otherwise "") pub picture_c: String, + /// Text of picture answer D (if existent, otherwise "") pub picture_d: String, } +// PUBLIC FUNCTION SECTION // +/// Out of the given set of questions, a new set of questions is returned +/// which includes only the questions that are a part of the config-allowed +/// categories. pub fn get_eligible_questions(questions: &Vec, config: &Config) -> Vec { let mut eligible_questions = Vec::new(); for question in questions {