From 379a9d449e3292ad075892d05cbc3824f6750ded Mon Sep 17 00:00:00 2001 From: mzums <120105518+mzums@users.noreply.github.com> Date: Sat, 21 Jun 2025 09:13:09 +0200 Subject: [PATCH 1/3] morse code learner --- submissions/morse_code_learner/Cargo.lock | 667 +++++++++++ submissions/morse_code_learner/Cargo.toml | 12 + submissions/morse_code_learner/LICENSE | 21 + submissions/morse_code_learner/README.md | 49 + .../morse_code_learner/common_words.txt | 1000 +++++++++++++++++ submissions/morse_code_learner/image.png | Bin 0 -> 16748 bytes submissions/morse_code_learner/src/main.rs | 613 ++++++++++ 7 files changed, 2362 insertions(+) create mode 100644 submissions/morse_code_learner/Cargo.lock create mode 100644 submissions/morse_code_learner/Cargo.toml create mode 100644 submissions/morse_code_learner/LICENSE create mode 100644 submissions/morse_code_learner/README.md create mode 100644 submissions/morse_code_learner/common_words.txt create mode 100644 submissions/morse_code_learner/image.png create mode 100644 submissions/morse_code_learner/src/main.rs diff --git a/submissions/morse_code_learner/Cargo.lock b/submissions/morse_code_learner/Cargo.lock new file mode 100644 index 00000000..67339053 --- /dev/null +++ b/submissions/morse_code_learner/Cargo.lock @@ -0,0 +1,667 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "bitflags" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" + +[[package]] +name = "bumpalo" +version = "3.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee" + +[[package]] +name = "cc" +version = "1.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc" +dependencies = [ + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" + +[[package]] +name = "chrono" +version = "0.4.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-link", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "directories" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16f5094c54661b38d03bd7e50df373292118db60b585c08a411c6d840017fe7d" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "getrandom" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", +] + +[[package]] +name = "hashbrown" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" + +[[package]] +name = "iana-time-zone" +version = "0.1.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "indexmap" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "js-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "libc" +version = "0.2.173" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8cfeafaffdbc32176b64fb251369d52ea9f0a8fbc6f8759edffef7b525d64bb" + +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags", + "libc", +] + +[[package]] +name = "log" +version = "0.4.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" + +[[package]] +name = "memchr" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" + +[[package]] +name = "morse_code_learner" +version = "0.1.0" +dependencies = [ + "chrono", + "directories", + "rand", + "serde", + "serde_derive", + "toml", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro2" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + +[[package]] +name = "rand" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" +dependencies = [ + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.3", +] + +[[package]] +name = "redox_users" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b" +dependencies = [ + "getrandom 0.2.16", + "libredox", + "thiserror", +] + +[[package]] +name = "rustversion" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" + +[[package]] +name = "serde" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "syn" +version = "2.0.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4307e30089d6fd6aff212f2da3a1f9e32f3223b1f010fb09b7c95f90f3ca1e8" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "toml" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "toml_write", + "winnow", +] + +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasi" +version = "0.14.2+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "windows-core" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.53.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + +[[package]] +name = "winnow" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd" +dependencies = [ + "memchr", +] + +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags", +] + +[[package]] +name = "zerocopy" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/submissions/morse_code_learner/Cargo.toml b/submissions/morse_code_learner/Cargo.toml new file mode 100644 index 00000000..6ce10061 --- /dev/null +++ b/submissions/morse_code_learner/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "morse_code_learner" +version = "0.1.0" +edition = "2021" + +[dependencies] +chrono = "0.4.41" +directories = "6.0.0" +rand = "0.9.1" +serde = "1.0.219" +serde_derive = "1.0.219" +toml = "0.8.23" diff --git a/submissions/morse_code_learner/LICENSE b/submissions/morse_code_learner/LICENSE new file mode 100644 index 00000000..bd8ddd13 --- /dev/null +++ b/submissions/morse_code_learner/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 mzums + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/submissions/morse_code_learner/README.md b/submissions/morse_code_learner/README.md new file mode 100644 index 00000000..67e86461 --- /dev/null +++ b/submissions/morse_code_learner/README.md @@ -0,0 +1,49 @@ +# morse_code_learner + +A command-line application for learning Morse code through encoding practice with individual characters and full words. + +![alt text](image.png) + +## Features +- **Progressive Learning System**: 8 character levels + 1 word level +- **Character Encoding**: Practice individual letters and numbers +- **Word Encoding**: Practice encoding common words after mastering characters +- **Performance Tracking**: Detailed statistics for each session +- **Progress Saving**: Automatic saving of learning progress between sessions +- **Adaptive Difficulty**: Automatic progression based on performance + + +## Installation +1. Ensure you have Rust installed +2. Close the repository: + ``` + git clone https://github.com/mzums/morse_code_learner.git + ``` +3. Build the app: + ``` + cd morse_code_learner + cargo build --release + ``` + +## Usage +Run the application: +``` +cargo run --release +``` + +#### The program will automatically: +1. Create configuration files if they don't exist +2. Load your previous progress +3. Start a new learning session based on your current level + +## Dependencies +You should have Rust installed! +- chrono = "0.4.41" +- directories = "6.0.0" +- rand = "0.9.1" +- serde = "1.0.219" +- serde_derive = "1.0.219" +- toml = "0.8.23" + +## Why? +I created this cool because I wanted to learn Morse code. But simply learning it from a website would be too boring. \ No newline at end of file diff --git a/submissions/morse_code_learner/common_words.txt b/submissions/morse_code_learner/common_words.txt new file mode 100644 index 00000000..e1122b9a --- /dev/null +++ b/submissions/morse_code_learner/common_words.txt @@ -0,0 +1,1000 @@ +as +I +his +that +he +was +for +on +are +with +they +be +at +one +have +this +from +by +hot +word +but +what +some +is +it +you +or +had +the +of +to +and +a +in +we +can +out +other +were +which +do +their +time +if +will +how +said +an +each +tell +does +set +three +want +air +well +also +play +small +end +put +home +read +hand +port +large +spell +add +even +land +here +must +big +high +such +follow +act +why +ask +men +change +went +light +kind +off +need +house +picture +try +us +again +animal +point +mother +world +near +build +self +earth +father +any +new +work +part +take +get +place +made +live +where +after +back +little +only +round +man +year +came +show +every +good +me +give +our +under +name +very +through +just +form +sentence +great +think +say +help +low +line +differ +turn +cause +much +mean +before +move +right +boy +old +too +same +she +all +there +when +up +use +your +way +about +many +then +them +write +would +like +so +these +her +long +make +thing +see +him +two +has +look +more +day +could +go +come +did +number +sound +no +most +people +my +over +know +water +than +call +first +who +may +down +side +been +now +find +head +stand +own +page +should +country +found +answer +school +grow +study +still +learn +plant +cover +food +sun +four +between +state +keep +eye +never +last +let +thought +city +tree +cross +farm +hard +start +might +story +saw +far +sea +draw +left +late +run +don’t +while +press +close +night +real +life +few +north +book +carry +took +science +eat +room +friend +began +idea +fish +mountain +stop +once +base +hear +horse +cut +sure +watch +color +face +wood +main +open +seem +together +next +white +children +begin +got +walk +example +ease +paper +group +always +music +those +both +mark +often +letter +until +mile +river +car +feet +care +second +enough +plain +girl +usual +young +ready +above +ever +red +list +though +feel +talk +bird +soon +body +dog +family +direct +pose +leave +song +measure +door +product +black +short +numeral +class +wind +question +happen +complete +ship +area +half +rock +order +fire +south +problem +piece +told +knew +pass +since +top +whole +king +street +inch +multiply +nothing +course +stay +wheel +full +force +blue +object +decide +surface +deep +moon +island +foot +system +busy +test +record +boat +common +gold +possible +plane +stead +dry +wonder +laugh +thousand +ago +ran +check +game +shape +equate +hot +miss +brought +heat +snow +tire +bring +yes +distant +fill +east +paint +language +among +unit +power +town +fine +certain +fly +fall +lead +cry +dark +machine +note +wait +plan +figure +star +box +noun +field +rest +correct +able +pound +done +beauty +drive +stood +contain +front +teach +week +final +gave +green +oh +quick +develop +ocean +warm +free +minute +strong +special +mind +behind +clear +tail +produce +fact +space +heard +best +hour +better +true +during +hundred +five +remember +step +early +hold +west +ground +interest +reach +fast +verb +sing +listen +six +table +travel +less +morning +ten +simple +several +vowel +toward +war +lay +against +pattern +slow +center +love +person +money +serve +appear +road +map +rain +rule +govern +pull +cold +notice +voice +energy +hunt +probable +bed +brother +egg +ride +cell +believe +perhaps +pick +sudden +count +square +reason +length +represent +art +subject +region +size +vary +settle +speak +weight +general +ice +matter +circle +pair +include +divide +syllable +felt +grand +ball +yet +wave +drop +heart +am +present +heavy +dance +engine +position +arm +wide +sail +material +fraction +forest +sit +race +window +store +summer +train +sleep +prove +lone +leg +exercise +wall +catch +mount +wish +sky +board +joy +winter +sat +written +wild +instrument +kept +glass +grass +cow +job +edge +sign +visit +past +soft +fun +bright +gas +weather +month +million +bear +finish +happy +hope +flower +clothe +strange +gone +trade +melody +trip +office +receive +row +mouth +exact +symbol +die +least +trouble +shout +except +wrote +seed +tone +join +suggest +clean +break +lady +yard +rise +bad +blow +oil +blood +touch +grew +cent +mix +team +wire +cost +lost +brown +wear +garden +equal +sent +choose +fell +fit +flow +fair +bank +collect +save +control +decimal +ear +else +quite +broke +case +middle +kill +son +lake +moment +scale +loud +spring +observe +child +straight +consonant +nation +dictionary +milk +speed +method +organ +pay +age +section +dress +cloud +surprise +quiet +stone +tiny +climb +cool +design +poor +lot +experiment +bottom +key +iron +single +stick +flat +twenty +skin +smile +crease +hole +jump +baby +eight +village +meet +root +buy +raise +solve +metal +whether +push +seven +paragraph +third +shall +held +hair +describe +cook +floor +either +result +burn +hill +safe +cat +century +consider +type +law +bit +coast +copy +phrase +silent +tall +sand +soil +roll +temperature +finger +industry +value +fight +lie +beat +excite +natural +view +sense +capital +won’t +chair +danger +fruit +rich +thick +soldier +process +operate +practice +separate +difficult +doctor +please +protect +noon +crop +modern +element +hit +student +corner +party +supply +whose +locate +ring +character +insect +caught +period +indicate +radio +spoke +atom +human +history +effect +electric +expect +bone +rail +imagine +provide +agree +thus +gentle +woman +captain +guess +necessary +sharp +wing +create +neighbor +wash +bat +rather +crowd +corn +compare +poem +string +bell +depend +meat +rub +tube +famous +dollar +stream +fear +sight +thin +triangle +planet +hurry +chief +colony +clock +mine +tie +enter +major +fresh +search +send +yellow +gun +allow +print +dead +spot +desert +suit +current +lift +rose +arrive +master +track +parent +shore +division +sheet +substance +favor +connect +post +spend +chord +fat +glad +original +share +station +dad +bread +charge +proper +bar +offer +segment +slave +duck +instant +market +degree +populate +chick +dear +enemy +reply +drink +occur +support +speech +nature +range +steam +motion +path +liquid +log +meant +quotient +teeth +shell +neck +oxygen +sugar +death +pretty +skill +women +season +solution +magnet +silver +thank +branch +match +suffix +especially +fig +afraid +huge +sister +steel +discuss +forward +similar +guide +experience +score +apple +bought +led +pitch +coat +mass +card +band +rope +slip +win +dream +evening +condition +feed +tool +total +basic +smell +valley +nor +double +seat +continue +block +chart +hat +sell +success +company +subtract +event +particular +deal +swim +term +opposite +wife +shoe +shoulder +spread +arrange +camp +invent +cotton +born +determine +quart +nine +truck +noise +level +chance +gather +shop +stretch +throw +shine +property +column +molecule +select +wrong +gray +repeat +require +broad +prepare +salt +nose +plural +anger +claim +continent diff --git a/submissions/morse_code_learner/image.png b/submissions/morse_code_learner/image.png new file mode 100644 index 0000000000000000000000000000000000000000..c01af400a9d6690a244ed65764d64ae9e89c5068 GIT binary patch literal 16748 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, +} + +impl Default for AppConfig { + fn default() -> Self { + AppConfig { + difficulty_level: 1, + session_duration: 5, + known_chars: vec![], + } + } +} + +#[derive(Debug, Serialize, Deserialize, Default)] +struct UserStats { + sessions_completed: u32, + chars_learned: u32, + words_learned: u32, + accuracy: f32, + #[serde(serialize_with = "serialize_response_times")] + #[serde(deserialize_with = "deserialize_response_times")] + response_times: HashMap, + word_response_times: HashMap, + session_history: Vec, +} + +fn serialize_response_times( + map: &HashMap, + serializer: S, +) -> Result +where + S: serde::Serializer, +{ + let string_map: HashMap = map + .iter() + .map(|(k, v)| (k.to_string(), *v)) + .collect(); + string_map.serialize(serializer) +} + +fn deserialize_response_times<'de, D>( + deserializer: D, +) -> Result, D::Error> +where + D: serde::Deserializer<'de>, +{ + let string_map = HashMap::::deserialize(deserializer)?; + let char_map = string_map + .into_iter() + .map(|(k, v)| (k.chars().next().unwrap(), v)) + .collect(); + Ok(char_map) +} + +#[derive(Debug, Serialize, Deserialize)] +struct LearningSession { + timestamp: String, + duration: u32, + chars_practiced: Vec, + words_practiced: Vec, + accuracy: f32, + difficulty: u8, +} + +#[derive(Debug)] +struct ProgressionSystem { + levels: Vec, + common_words: Vec, +} + +#[derive(Debug)] +struct ProgressionLevel { + level: u8, + chars_to_learn: Vec, + speed_requirement: f32, + accuracy_requirement: f32, +} + +struct MorseTutor { + config: AppConfig, + stats: UserStats, + progression: ProgressionSystem, + practice_queue: VecDeque, + session_start: Instant, + correct_answers: u32, + total_answers: u32, + is_word_level: bool, + rng: ThreadRng, +} + +impl MorseTutor { + fn new() -> Self { + let config = AppConfig::load().unwrap_or_default(); + let stats = UserStats::load().unwrap_or_default(); + let progression = ProgressionSystem::new(); + + let is_word_level = config.difficulty_level >= 9; + + MorseTutor { + config: config.clone(), + stats, + progression, + practice_queue: VecDeque::new(), + session_start: Instant::now(), + correct_answers: 0, + total_answers: 0, + is_word_level, + rng: rand::rng(), + } + } + + fn generate_practice_queue(&mut self) { + self.practice_queue.clear(); + + if self.is_word_level { + let mut selected_words = self.progression.common_words.clone(); + selected_words.shuffle(&mut self.rng); + + for word in selected_words.into_iter().take(10) { + self.practice_queue.push_back(word); + } + } else { + let mut chars = self.config.known_chars.clone(); + chars.shuffle(&mut self.rng); + + if let Some(level) = self.progression.levels.iter() + .find(|l| l.level == self.config.difficulty_level) + { + for c in &level.chars_to_learn { + if !chars.contains(c) { + chars.push(*c); + } + } + } + + for _ in 0..5 { + for c in &chars { + self.practice_queue.push_back(c.to_string()); + } + } + } + } + + fn end_session(&mut self) { + let duration = self.session_start.elapsed().as_secs() as u32; + let accuracy = if self.total_answers > 0 { + self.correct_answers as f32 / self.total_answers as f32 + } else { + 0.0 + }; + + if let Some(session) = self.stats.session_history.last_mut() { + session.duration = duration; + session.accuracy = accuracy; + + if self.is_word_level { + session.words_practiced = self.practice_queue.iter().cloned().collect(); + } else { + session.chars_practiced = self.practice_queue.iter() + .filter_map(|s| s.chars().next()) + .collect(); + } + } + + self.stats.sessions_completed += 1; + self.stats.accuracy = (self.stats.accuracy * (self.stats.sessions_completed - 1) as f32 + accuracy) / + self.stats.sessions_completed as f32; + + if let Err(e) = self.config.save() { + eprintln!("Error saving configuration: {}", e); + } + + if let Err(e) = self.stats.save() { + eprintln!("Error saving stats: {}", e); + } + + self.show_summary(); + self.update_progression(); + } + + fn practice_item(&mut self, item: &str) -> bool { + let morse_code = if self.is_word_level { + self.encode_word(item) + } else { + Self::char_to_morse(item.chars().next().unwrap()) + .map(|s| s.to_string()) + .unwrap_or_default() + }; + + println!("\n--- New {} ---", if self.is_word_level { "Word" } else { "Character" }); + println!("Level: {} | Exercises left: {}", + self.config.difficulty_level, + self.practice_queue.len() + ); + println!("{}: {}", if self.is_word_level { "Word" } else { "Character" }, item); + + print!("Your Morse code: "); + io::stdout().flush().unwrap(); + + let start_time = Instant::now(); + let mut input = String::new(); + io::stdin().read_line(&mut input).expect("Error reading input"); + let response_time = start_time.elapsed().as_secs_f32(); + + let input = input.trim().to_uppercase(); + let correct = input == morse_code; + + self.total_answers += 1; + + if self.is_word_level { + self.stats.word_response_times.insert(item.to_string(), response_time); + self.stats.words_learned += 1; + } else { + if let Some(c) = item.chars().next() { + self.stats.response_times.insert(c, response_time); + self.stats.chars_learned += 1; + } + } + + if correct { + self.correct_answers += 1; + println!("✓ Correct! (time: {:.1}s)", response_time); + } else { + println!("✗ Incorrect! Correct code: {} (your: {})", morse_code, input); + } + + correct + } + + fn char_to_morse(c: char) -> Option<&'static str> { + MORSE_MAPPING.iter() + .find(|(ch, _)| *ch == c.to_ascii_uppercase()) + .map(|(_, code)| *code) + } + + fn encode_word(&self, word: &str) -> String { + word.chars() + .filter_map(Self::char_to_morse) + .collect::>() + .join(" ") + } + + fn start_session(&mut self) { + self.generate_practice_queue(); + + println!("\nNew session started!"); + println!("Difficulty level: {}", self.config.difficulty_level); + + if self.is_word_level { + println!("Mode: Word Practice (10 common words)"); + } else { + if let Some(level) = self.progression.levels.iter() + .find(|l| l.level == self.config.difficulty_level) + { + let mut chars: Vec = self.config.known_chars.clone(); + for c in &level.chars_to_learn { + if !chars.contains(c) { + chars.push(*c); + } + } + println!("Characters to learn: {}", chars.iter().collect::()); + } else { + println!("Characters to learn: {}", self.config.known_chars.iter().collect::()); + } + } + + println!("Exercise number: {}", self.practice_queue.len()); + println!("------------------------------------------------"); + + self.session_start = Instant::now(); + self.stats.session_history.push(LearningSession { + timestamp: chrono::Local::now().to_rfc3339(), + duration: 0, + chars_practiced: vec![], + words_practiced: vec![], + accuracy: 0.0, + difficulty: self.config.difficulty_level, + }); + + self.correct_answers = 0; + self.total_answers = 0; + } + + fn run(&mut self) { + self.start_session(); + while let Some(current_item) = self.practice_queue.front().cloned() { + if self.session_start.elapsed().as_secs() > self.config.session_duration as u64 * 60 + { + println!("\n⏰ Time passed!"); + break; + } + + let correct = self.practice_item(¤t_item); + + if correct { + self.practice_queue.pop_front(); + } else { + if let Some(item) = self.practice_queue.pop_front() { + self.practice_queue.push_back(item); + } + } + + print!("Press 'q' to quit or Enter to continue: "); + io::stdout().flush().unwrap(); + + let mut input = String::new(); + io::stdin().read_line(&mut input).expect("Error reading input"); + + if input.trim().eq_ignore_ascii_case("q") { + println!("\nSession interrupted"); + break; + } + } + + self.end_session(); + } + + fn show_summary(&self) { + let duration = self.session_start.elapsed().as_secs() as u32; + let minutes = duration / 60; + let seconds = duration % 60; + let accuracy = if self.total_answers > 0 { + (self.correct_answers as f32 / self.total_answers as f32) * 100.0 + } else { + 0.0 + }; + + println!("\n================================================"); + println!(" SESSION SUMMARY"); + println!("================================================"); + println!("Duration: {:02}:{:02}", minutes, seconds); + println!("Exercise number: {}", self.total_answers); + println!("Correct answers: {}/{} ({:.1}%)", + self.correct_answers, self.total_answers, accuracy); + println!("Difficulty: {}", self.config.difficulty_level); + + if self.is_word_level { + if !self.stats.word_response_times.is_empty() { + println!("\nWord statistics:"); + for (word, time) in &self.stats.word_response_times { + println!(" {}: {:.1}s", word, time); + } + + let avg_time: f32 = self.stats.word_response_times.values().sum::() / + self.stats.word_response_times.len() as f32; + println!("Average reaction time: {:.1}s", avg_time); + } + } else { + if !self.stats.response_times.is_empty() { + println!("\nCharacter statistics:"); + for (c, time) in &self.stats.response_times { + println!(" {}: {:.1}s", c, time); + } + + let avg_time: f32 = self.stats.response_times.values().sum::() / + self.stats.response_times.len() as f32; + println!("Average reaction time: {:.1}s", avg_time); + } + } + + println!("================================================"); + } + + fn update_progression(&mut self) { + let current_level = self.config.difficulty_level; + + if self.is_word_level { + println!("\nCongrats! You're practicing words!"); + println!("Continue to improve your word encoding speed."); + return; + } + + if let Some(level) = self.progression.levels.iter().find(|l| l.level == current_level) { + let accuracy = if self.total_answers > 0 { + self.correct_answers as f32 / self.total_answers as f32 + } else { + 0.0 + }; + + let avg_time = if !self.stats.response_times.is_empty() { + self.stats.response_times.values().sum::() / + self.stats.response_times.len() as f32 + } else { + 0.0 + }; + + println!("\nLevel requirements {}:", current_level); + println!("- Accuracy: {:.1}% (required: {:.1}%)", + accuracy * 100.0, level.accuracy_requirement * 100.0); + + println!("- Average time: {:.1}s (required: {:.1}s)", + avg_time, level.speed_requirement); + + if avg_time <= level.speed_requirement && accuracy >= level.accuracy_requirement { + self.config.difficulty_level += 1; + println!("\n🎉 Advanced to level {}!", self.config.difficulty_level); + + if self.config.difficulty_level == 9 { + self.is_word_level = true; + println!("🌟 CONGRATULATIONS! You've reached word level!"); + println!("Now you'll practice encoding common words."); + } else { + if let Some(next_level) = self.progression.levels.iter() + .find(|l| l.level == self.config.difficulty_level) + { + for c in &next_level.chars_to_learn { + if !self.config.known_chars.contains(c) { + self.config.known_chars.push(*c); + println!("+ New char added: {}", c); + } + } + } + } + + self.generate_practice_queue(); + } else { + println!("\nℹ️ Continue practicing on current level."); + } + + if let Err(e) = self.config.save() { + eprintln!("Error saving configuration: {}", e); + } + } + } +} + +impl AppConfig { + fn config_path() -> PathBuf { + PathBuf::from("morse_config.toml") + } + + fn load() -> Result> { + let path = Self::config_path(); + if path.exists() { + let data = fs::read_to_string(&path)?; + toml::from_str(&data).map_err(|e| e.into()) + } else { + let config = AppConfig::default(); + config.save()?; + Ok(config) + } + } + + fn save(&self) -> Result<(), Box> { + let path = Self::config_path(); + if let Some(parent) = path.parent() { + fs::create_dir_all(parent)?; + } + + let data = toml::to_string(self)?; + fs::write(&path, data)?; + Ok(()) + } +} + +impl UserStats { + fn stats_path() -> PathBuf { + PathBuf::from("morse_stats.toml") + } + + fn load() -> Result> { + let path = Self::stats_path(); + if path.exists() { + let data = fs::read_to_string(&path)?; + toml::from_str(&data).map_err(|e| e.into()) + } else { + Ok(UserStats::default()) + } + } + + fn save(&self) -> Result<(), Box> { + let path = Self::stats_path(); + if let Some(parent) = path.parent() { + fs::create_dir_all(parent)?; + } + let data = toml::to_string(self)?; + fs::write(path, data)?; + Ok(()) + } +} + +impl ProgressionSystem { + fn new() -> Self { + let levels = vec![ + ProgressionLevel { + level: 1, + chars_to_learn: vec!['E', 'T'], + speed_requirement: 5.0, + accuracy_requirement: 0.8, + }, + ProgressionLevel { + level: 2, + chars_to_learn: vec!['A', 'I', 'M', 'N'], + speed_requirement: 4.0, + accuracy_requirement: 0.85, + }, + ProgressionLevel { + level: 3, + chars_to_learn: vec!['D', 'G', 'K', 'O'], + speed_requirement: 3.5, + accuracy_requirement: 0.9, + }, + ProgressionLevel { + level: 4, + chars_to_learn: vec!['R', 'S', 'U', 'W'], + speed_requirement: 3.5, + accuracy_requirement: 0.9, + }, + ProgressionLevel { + level: 5, + chars_to_learn: vec!['B', 'C', 'F', 'H', 'J', 'L'], + speed_requirement: 3.0, + accuracy_requirement: 0.95, + }, + ProgressionLevel { + level: 6, + chars_to_learn: vec!['P', 'Q', 'V', 'X', 'Y', 'Z'], + speed_requirement: 3.0, + accuracy_requirement: 0.95, + }, + ProgressionLevel { + level: 7, + chars_to_learn: vec!['0', '1', '2', '3', '4'], + speed_requirement: 2.5, + accuracy_requirement: 0.95, + }, + ProgressionLevel { + level: 8, + chars_to_learn: vec!['5', '6', '7', '8', '9'], + speed_requirement: 2.5, + accuracy_requirement: 0.95, + }, + ]; + + let common_words = match fs::read_to_string("common_words.txt") { + Ok(contents) => { + contents.lines() + .map(|s| s.trim().to_uppercase()) + .filter(|s| !s.is_empty()) + .collect() + } + Err(_) => { + println!("Warning: common_words.txt not found. Using default words."); + vec![ + "THE".to_string(), + "BE".to_string(), + "TO".to_string(), + "OF".to_string(), + "AND".to_string(), + "A".to_string(), + "IN".to_string(), + "THAT".to_string(), + "HAVE".to_string(), + "I".to_string(), + "IT".to_string(), + "FOR".to_string(), + "NOT".to_string(), + "ON".to_string(), + "WITH".to_string(), + "HE".to_string(), + "AS".to_string(), + "YOU".to_string(), + "DO".to_string(), + "AT".to_string(), + ] + } + }; + + ProgressionSystem { + levels, + common_words, + } + } +} + +fn main() { + println!("================================================"); + println!(" MORSE CODE LEARNER"); + println!("================================================"); + println!("Progression system:"); + println!("- Levels 1-8: Character encoding"); + println!("- Level 9: Word encoding"); + println!("================================================"); + + let mut app = MorseTutor::new(); + app.run(); +} From edc01fda0ccfb637d75c1bf31afe3168f42d503b Mon Sep 17 00:00:00 2001 From: mzums <120105518+mzums@users.noreply.github.com> Date: Tue, 24 Jun 2025 18:20:50 +0200 Subject: [PATCH 2/3] audio added --- submissions/morse_code_learner/src/main.rs | 47 ++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/submissions/morse_code_learner/src/main.rs b/submissions/morse_code_learner/src/main.rs index e5c2a609..33f802dd 100644 --- a/submissions/morse_code_learner/src/main.rs +++ b/submissions/morse_code_learner/src/main.rs @@ -9,6 +9,12 @@ use rand::{seq::SliceRandom, rngs::ThreadRng}; use serde_derive::{Serialize, Deserialize}; use serde::{Deserialize, Serialize}; use chrono; +use rodio::{source::SineWave, OutputStream, Sink, Source}; +use std::thread; + + +const DOT_DURATION_MS: u64 = 80; +const DASH_DURATION_MS: u64 = 500; const MORSE_MAPPING: [(char, &str); 36] = [ ('A', ".-"), ('B', "-..."), ('C', "-.-."), ('D', "-.."), ('E', "."), ('F', "..-."), @@ -37,6 +43,42 @@ impl Default for AppConfig { } } +fn play_morse_code(morse_code: &str) { + let (_stream, stream_handle) = match OutputStream::try_default() { + Ok(stream) => stream, + Err(e) => { + eprintln!("Error creating audio output: {}", e); + return; + } + }; + + let sink = match Sink::try_new(&stream_handle) { + Ok(sink) => sink, + Err(e) => { + eprintln!("Error creating audio sink: {}", e); + return; + } + }; + + for symbol in morse_code.chars() { + match symbol { + '.' => play_beep(&sink, DOT_DURATION_MS), + '-' => play_beep(&sink, DASH_DURATION_MS), + ' ' => thread::sleep(std::time::Duration::from_millis(3 * DOT_DURATION_MS)), + _ => {} + } + thread::sleep(std::time::Duration::from_millis(DOT_DURATION_MS)); + } +} + +fn play_beep(sink: &Sink, duration_ms: u64) { + let source = SineWave::new(600.0) + .take_duration(std::time::Duration::from_millis(duration_ms)) + .amplify(0.2); + sink.append(source); + thread::sleep(std::time::Duration::from_millis(duration_ms)); +} + #[derive(Debug, Serialize, Deserialize, Default)] struct UserStats { sessions_completed: u32, @@ -249,6 +291,11 @@ impl MorseTutor { } else { println!("✗ Incorrect! Correct code: {} (your: {})", morse_code, input); } + + let morse_audio = morse_code.clone(); + thread::spawn(move || { + play_morse_code(&morse_audio); + }); correct } From b753736b9b10331ff1ada22cc6c14d7e1ecb0c51 Mon Sep 17 00:00:00 2001 From: mzums <120105518+mzums@users.noreply.github.com> Date: Thu, 26 Jun 2025 21:56:33 +0200 Subject: [PATCH 3/3] with audio --- submissions/morse_code_learner/Cargo.lock | 785 +++++++++++++++++- submissions/morse_code_learner/Cargo.toml | 1 + submissions/morse_code_learner/README.md | 1 + .../morse_code_learner/morse_config.toml | 3 + .../morse_code_learner/morse_stats.toml | 54 ++ 5 files changed, 828 insertions(+), 16 deletions(-) create mode 100644 submissions/morse_code_learner/morse_config.toml create mode 100644 submissions/morse_code_learner/morse_stats.toml diff --git a/submissions/morse_code_learner/Cargo.lock b/submissions/morse_code_learner/Cargo.lock index 67339053..2a2414f4 100644 --- a/submissions/morse_code_learner/Cargo.lock +++ b/submissions/morse_code_learner/Cargo.lock @@ -2,6 +2,37 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "alsa" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed7572b7ba83a31e20d1b48970ee402d2e3e0537dcfe0a3ff4d6eb7508617d43" +dependencies = [ + "alsa-sys", + "bitflags 2.9.1", + "cfg-if", + "libc", +] + +[[package]] +name = "alsa-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db8fee663d06c4e303404ef5f40488a53e062f89ba8bfed81f42325aafad1527" +dependencies = [ + "libc", + "pkg-config", +] + [[package]] name = "android-tzdata" version = "0.1.1" @@ -17,12 +48,42 @@ dependencies = [ "libc", ] +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + [[package]] name = "autocfg" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +[[package]] +name = "bindgen" +version = "0.72.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f72209734318d0b619a5e0f5129918b848c416e122a3c4ce054e03cb87b726f" +dependencies = [ + "bitflags 2.9.1", + "cexpr", + "clang-sys", + "itertools", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + [[package]] name = "bitflags" version = "2.9.1" @@ -35,15 +96,50 @@ version = "3.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee" +[[package]] +name = "bytemuck" +version = "1.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c76a5792e44e4abe34d3abf15636779261d45a7450612059293d1d2cfc63422" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" + [[package]] name = "cc" version = "1.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc" dependencies = [ + "jobserver", + "libc", "shlex", ] +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + [[package]] name = "cfg-if" version = "1.0.1" @@ -64,12 +160,88 @@ dependencies = [ "windows-link", ] +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "claxon" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bfbf56724aa9eca8afa4fcfadeb479e722935bb2a0900c2d37e0cc477af0688" + +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + [[package]] name = "core-foundation-sys" version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "coreaudio-rs" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "321077172d79c662f64f5071a03120748d5bb652f5231570141be24cfcd2bace" +dependencies = [ + "bitflags 1.3.2", + "core-foundation-sys", + "coreaudio-sys", +] + +[[package]] +name = "coreaudio-sys" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ceec7a6067e62d6f931a2baf6f3a751f4a892595bcec1461a3c94ef9949864b6" +dependencies = [ + "bindgen", +] + +[[package]] +name = "cpal" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "873dab07c8f743075e57f524c583985fbaf745602acbe916a01539364369a779" +dependencies = [ + "alsa", + "core-foundation-sys", + "coreaudio-rs", + "dasp_sample", + "jni", + "js-sys", + "libc", + "mach2", + "ndk", + "ndk-context", + "oboe", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows", +] + +[[package]] +name = "dasp_sample" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c87e182de0887fd5361989c677c4e8f5000cd9491d6d563161a8f3a5519fc7f" + [[package]] name = "directories" version = "6.0.0" @@ -88,7 +260,22 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys", + "windows-sys 0.60.2", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", ] [[package]] @@ -120,12 +307,24 @@ dependencies = [ "wasi 0.14.2+wasi-0.2.4", ] +[[package]] +name = "glob" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" + [[package]] name = "hashbrown" version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" +[[package]] +name = "hound" +version = "3.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62adaabb884c94955b19907d60019f4e145d091c75345379e70d1ee696f7854f" + [[package]] name = "iana-time-zone" version = "0.1.63" @@ -138,7 +337,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core", + "windows-core 0.61.2", ] [[package]] @@ -160,6 +359,47 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "jni-sys", + "log", + "thiserror 1.0.69", + "walkdir", + "windows-sys 0.45.0", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "jobserver" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" +dependencies = [ + "getrandom 0.3.3", + "libc", +] + [[package]] name = "js-sys" version = "0.3.77" @@ -170,19 +410,46 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "lewton" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "777b48df9aaab155475a83a7df3070395ea1ac6902f5cd062b8f2b028075c030" +dependencies = [ + "byteorder", + "ogg", + "tinyvec", +] + [[package]] name = "libc" version = "0.2.173" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8cfeafaffdbc32176b64fb251369d52ea9f0a8fbc6f8759edffef7b525d64bb" +[[package]] +name = "libloading" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" +dependencies = [ + "cfg-if", + "windows-targets 0.53.2", +] + [[package]] name = "libredox" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags", + "bitflags 2.9.1", "libc", ] @@ -192,12 +459,27 @@ version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +[[package]] +name = "mach2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d640282b302c0bb0a2a8e0233ead9035e3bed871f0b7e81fe4a1ec829765db44" +dependencies = [ + "libc", +] + [[package]] name = "memchr" version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "morse_code_learner" version = "0.1.0" @@ -205,11 +487,62 @@ dependencies = [ "chrono", "directories", "rand", + "rodio", "serde", "serde_derive", "toml", ] +[[package]] +name = "ndk" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2076a31b7010b17a38c01907c45b945e8f11495ee4dd588309718901b1f7a5b7" +dependencies = [ + "bitflags 2.9.1", + "jni-sys", + "log", + "ndk-sys", + "num_enum", + "thiserror 1.0.69", +] + +[[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + +[[package]] +name = "ndk-sys" +version = "0.5.0+25.2.9519653" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691" +dependencies = [ + "jni-sys", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -219,6 +552,60 @@ dependencies = [ "autocfg", ] +[[package]] +name = "num_enum" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a973b4e44ce6cad84ce69d797acf9a044532e4184c4f267913d1b546a0727b7a" +dependencies = [ + "num_enum_derive", + "rustversion", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "oboe" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8b61bebd49e5d43f5f8cc7ee2891c16e0f41ec7954d36bcb6c14c5e0de867fb" +dependencies = [ + "jni", + "ndk", + "ndk-context", + "num-derive", + "num-traits", + "oboe-sys", +] + +[[package]] +name = "oboe-sys" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8bb09a4a2b1d668170cfe0a7d5bc103f8999fb316c98099b6a9939c9f2e79d" +dependencies = [ + "cc", +] + +[[package]] +name = "ogg" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6951b4e8bf21c8193da321bcce9c9dd2e13c858fe078bf9054a288b419ae5d6e" +dependencies = [ + "byteorder", +] + [[package]] name = "once_cell" version = "1.21.3" @@ -231,6 +618,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + [[package]] name = "ppv-lite86" version = "0.2.21" @@ -240,6 +633,15 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "proc-macro-crate" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" +dependencies = [ + "toml_edit", +] + [[package]] name = "proc-macro2" version = "1.0.95" @@ -301,15 +703,72 @@ checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b" dependencies = [ "getrandom 0.2.16", "libredox", - "thiserror", + "thiserror 2.0.12", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "rodio" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ceb6607dd738c99bc8cb28eff249b7cd5c8ec88b9db96c0608c1480d140fb1" +dependencies = [ + "claxon", + "cpal", + "hound", + "lewton", + "symphonia", ] +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + [[package]] name = "rustversion" version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "serde" version = "1.0.219" @@ -345,6 +804,55 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "symphonia" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "815c942ae7ee74737bb00f965fa5b5a2ac2ce7b6c01c0cc169bbeaf7abd5f5a9" +dependencies = [ + "lazy_static", + "symphonia-bundle-mp3", + "symphonia-core", + "symphonia-metadata", +] + +[[package]] +name = "symphonia-bundle-mp3" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c01c2aae70f0f1fb096b6f0ff112a930b1fb3626178fba3ae68b09dce71706d4" +dependencies = [ + "lazy_static", + "log", + "symphonia-core", + "symphonia-metadata", +] + +[[package]] +name = "symphonia-core" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "798306779e3dc7d5231bd5691f5a813496dc79d3f56bf82e25789f2094e022c3" +dependencies = [ + "arrayvec", + "bitflags 1.3.2", + "bytemuck", + "lazy_static", + "log", +] + +[[package]] +name = "symphonia-metadata" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc622b9841a10089c5b18e99eb904f4341615d5aa55bbf4eedde1be721a4023c" +dependencies = [ + "encoding_rs", + "lazy_static", + "log", + "symphonia-core", +] + [[package]] name = "syn" version = "2.0.103" @@ -356,13 +864,33 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + [[package]] name = "thiserror" version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" dependencies = [ - "thiserror-impl", + "thiserror-impl 2.0.12", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -376,6 +904,21 @@ dependencies = [ "syn", ] +[[package]] +name = "tinyvec" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "toml" version = "0.8.23" @@ -423,6 +966,16 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" @@ -464,6 +1017,19 @@ dependencies = [ "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +dependencies = [ + "cfg-if", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "wasm-bindgen-macro" version = "0.2.100" @@ -496,6 +1062,45 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "web-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "windows" +version = "0.54.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9252e5725dbed82865af151df558e754e4a3c2c30818359eb17465f1346a1b49" +dependencies = [ + "windows-core 0.54.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-core" +version = "0.54.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12661b9c89351d684a50a8a643ce5f608e20243b9fb84687800163429f161d65" +dependencies = [ + "windows-result 0.1.2", + "windows-targets 0.52.6", +] + [[package]] name = "windows-core" version = "0.61.2" @@ -505,7 +1110,7 @@ dependencies = [ "windows-implement", "windows-interface", "windows-link", - "windows-result", + "windows-result 0.3.4", "windows-strings", ] @@ -537,6 +1142,15 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" +[[package]] +name = "windows-result" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-result" version = "0.3.4" @@ -555,13 +1169,62 @@ dependencies = [ "windows-link", ] +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets", + "windows-targets 0.53.2", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] @@ -570,58 +1233,148 @@ version = "0.53.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + [[package]] name = "windows_aarch64_gnullvm" version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + [[package]] name = "windows_aarch64_msvc" version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + [[package]] name = "windows_i686_gnu" version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + [[package]] name = "windows_i686_gnullvm" version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + [[package]] name = "windows_i686_msvc" version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + [[package]] name = "windows_x86_64_gnu" version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + [[package]] name = "windows_x86_64_gnullvm" version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + [[package]] name = "windows_x86_64_msvc" version = "0.53.0" @@ -643,7 +1396,7 @@ version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" dependencies = [ - "bitflags", + "bitflags 2.9.1", ] [[package]] diff --git a/submissions/morse_code_learner/Cargo.toml b/submissions/morse_code_learner/Cargo.toml index 6ce10061..3a6fa876 100644 --- a/submissions/morse_code_learner/Cargo.toml +++ b/submissions/morse_code_learner/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" chrono = "0.4.41" directories = "6.0.0" rand = "0.9.1" +rodio = "0.20.1" serde = "1.0.219" serde_derive = "1.0.219" toml = "0.8.23" diff --git a/submissions/morse_code_learner/README.md b/submissions/morse_code_learner/README.md index 67e86461..77e45bc9 100644 --- a/submissions/morse_code_learner/README.md +++ b/submissions/morse_code_learner/README.md @@ -11,6 +11,7 @@ A command-line application for learning Morse code through encoding practice wit - **Performance Tracking**: Detailed statistics for each session - **Progress Saving**: Automatic saving of learning progress between sessions - **Adaptive Difficulty**: Automatic progression based on performance +- **Audio**: Playing Morse code as audio ## Installation diff --git a/submissions/morse_code_learner/morse_config.toml b/submissions/morse_code_learner/morse_config.toml new file mode 100644 index 00000000..54a3fc38 --- /dev/null +++ b/submissions/morse_code_learner/morse_config.toml @@ -0,0 +1,3 @@ +difficulty_level = 9 +session_duration = 5 +known_chars = ["A", "I", "M", "N"] diff --git a/submissions/morse_code_learner/morse_stats.toml b/submissions/morse_code_learner/morse_stats.toml new file mode 100644 index 00000000..faeac7cb --- /dev/null +++ b/submissions/morse_code_learner/morse_stats.toml @@ -0,0 +1,54 @@ +sessions_completed = 5 +chars_learned = 64 +words_learned = 0 +accuracy = 0.955731213092804 + +[response_times] +T = 0.860741138458252 +E = 1.4458223581314087 +N = 3.236259937286377 +I = 1.8315136432647705 +M = 1.7500873804092407 +A = 1.5086846351623535 + +[word_response_times] + +[[session_history]] +timestamp = "2025-06-23T18:00:14.464119132+02:00" +duration = 24 +chars_practiced = [] +words_practiced = [] +accuracy = 0.9090909361839294 +difficulty = 1 + +[[session_history]] +timestamp = "2025-06-23T18:00:52.561435916+02:00" +duration = 73 +chars_practiced = [] +words_practiced = [] +accuracy = 0.8695651888847351 +difficulty = 2 + +[[session_history]] +timestamp = "2025-06-24T16:23:03.191160718+02:00" +duration = 20 +chars_practiced = [] +words_practiced = [] +accuracy = 1.0 +difficulty = 1 + +[[session_history]] +timestamp = "2025-06-26T19:49:30.238909462+02:00" +duration = 25 +chars_practiced = [] +words_practiced = [] +accuracy = 1.0 +difficulty = 1 + +[[session_history]] +timestamp = "2025-06-26T19:52:01.189715364+02:00" +duration = 20 +chars_practiced = [] +words_practiced = [] +accuracy = 1.0 +difficulty = 1