mirror of
https://github.com/kmc7468/cs220.git
synced 2025-12-14 22:18:46 +00:00
add 8, 11, 12
This commit is contained in:
267
Cargo.lock
generated
267
Cargo.lock
generated
@@ -6,7 +6,16 @@ version = 3
|
|||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.66"
|
version = "1.0.66"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6"
|
checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "approx"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
@@ -47,11 +56,21 @@ version = "4.0.29"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4d63b9e9c07271b9957ad22c173bae2a4d9a81127680962039296abcd2f8251d"
|
checksum = "4d63b9e9c07271b9957ad22c173bae2a4d9a81127680962039296abcd2f8251d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"clap_builder",
|
||||||
"clap_derive",
|
"clap_derive",
|
||||||
"clap_lex",
|
|
||||||
"is-terminal",
|
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_builder"
|
||||||
|
version = "4.3.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c1458a1df40e1e2afebb7ab60ce55c1fa8f431146205aa5f4887e0b111c27636"
|
||||||
|
dependencies = [
|
||||||
|
"anstream",
|
||||||
|
"anstyle",
|
||||||
|
"bitflags",
|
||||||
|
"clap_lex",
|
||||||
"strsim",
|
"strsim",
|
||||||
"termcolor",
|
"termcolor",
|
||||||
]
|
]
|
||||||
@@ -145,14 +164,19 @@ name = "cs220"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
"approx",
|
||||||
"clap",
|
"clap",
|
||||||
"etrace",
|
"etrace",
|
||||||
"itertools",
|
"itertools",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
|
"ndarray",
|
||||||
|
"ndarray-rand",
|
||||||
"ntest",
|
"ntest",
|
||||||
|
"num-traits",
|
||||||
"pest",
|
"pest",
|
||||||
"pest_derive",
|
"pest_derive",
|
||||||
"rayon",
|
"rayon",
|
||||||
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -209,10 +233,27 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "heck"
|
name = "getrandom"
|
||||||
version = "0.4.0"
|
version = "0.2.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
|
checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"wasi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown"
|
||||||
|
version = "0.12.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "heck"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hermit-abi"
|
name = "hermit-abi"
|
||||||
@@ -225,11 +266,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hermit-abi"
|
name = "hermit-abi"
|
||||||
version = "0.2.6"
|
version = "0.3.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
|
checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "indexmap"
|
||||||
|
version = "1.9.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"autocfg",
|
||||||
|
"hashbrown",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -273,13 +321,35 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
|||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.138"
|
version = "0.2.138"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8"
|
checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libm"
|
||||||
|
version = "0.2.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linux-raw-sys"
|
name = "linux-raw-sys"
|
||||||
version = "0.1.3"
|
version = "0.1.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8f9f08d8963a6c613f4b1a78f4f4a4dbfadf8e6545b2d72861731e4858b8b47f"
|
checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "matrixmultiply"
|
||||||
|
version = "0.3.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "090126dc04f95dc0d1c1c91f61bdd474b3930ca064c1edc8a849da2c6cbe1e77"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"rawpointer",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memoffset"
|
name = "memoffset"
|
||||||
@@ -290,6 +360,30 @@ dependencies = [
|
|||||||
"autocfg",
|
"autocfg",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ndarray"
|
||||||
|
version = "0.15.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "adb12d4e967ec485a5f71c6311fe28158e9d6f4bc4a447b474184d0f91a8fa32"
|
||||||
|
dependencies = [
|
||||||
|
"matrixmultiply",
|
||||||
|
"num-complex",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
"rawpointer",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ndarray-rand"
|
||||||
|
version = "0.14.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "65608f937acc725f5b164dcf40f4f0bc5d67dc268ab8a649d3002606718c4588"
|
||||||
|
dependencies = [
|
||||||
|
"ndarray",
|
||||||
|
"rand",
|
||||||
|
"rand_distr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ntest"
|
name = "ntest"
|
||||||
version = "0.9.0"
|
version = "0.9.0"
|
||||||
@@ -320,7 +414,36 @@ dependencies = [
|
|||||||
"proc-macro-crate",
|
"proc-macro-crate",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn 1.0.109",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-complex"
|
||||||
|
version = "0.4.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-integer"
|
||||||
|
version = "0.1.45"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-traits"
|
||||||
|
version = "0.2.16"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"libm",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -335,15 +458,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.16.0"
|
version = "1.17.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
|
checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "os_str_bytes"
|
|
||||||
version = "6.4.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pest"
|
name = "pest"
|
||||||
@@ -389,6 +506,12 @@ dependencies = [
|
|||||||
"sha1",
|
"sha1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ppv-lite86"
|
||||||
|
version = "0.2.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro-crate"
|
name = "proc-macro-crate"
|
||||||
version = "1.2.1"
|
version = "1.2.1"
|
||||||
@@ -442,6 +565,52 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand"
|
||||||
|
version = "0.8.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"rand_chacha",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_chacha"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||||
|
dependencies = [
|
||||||
|
"ppv-lite86",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.6.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_distr"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
"rand",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rawpointer"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rayon"
|
name = "rayon"
|
||||||
version = "1.6.0"
|
version = "1.6.0"
|
||||||
@@ -486,16 +655,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "sha2"
|
||||||
version = "1.0.149"
|
version = "0.10.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "256b9932320c590e707b94576e3cc1f7c9024d0ee6612dfbcf1cb106cbe8e055"
|
checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "sha1"
|
|
||||||
version = "0.10.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"cpufeatures",
|
"cpufeatures",
|
||||||
@@ -582,41 +745,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi"
|
name = "wasi"
|
||||||
version = "0.3.9"
|
version = "0.11.0+wasi-snapshot-preview1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||||
dependencies = [
|
|
||||||
"winapi-i686-pc-windows-gnu",
|
|
||||||
"winapi-x86_64-pc-windows-gnu",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi-i686-pc-windows-gnu"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi-util"
|
|
||||||
version = "0.1.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
|
||||||
dependencies = [
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi-x86_64-pc-windows-gnu"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.42.0"
|
version = "0.48.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
|
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-targets"
|
||||||
|
version = "0.48.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows_aarch64_gnullvm",
|
"windows_aarch64_gnullvm",
|
||||||
"windows_aarch64_msvc",
|
"windows_aarch64_msvc",
|
||||||
|
|||||||
@@ -14,4 +14,9 @@ lazy_static = "1.4.0"
|
|||||||
pest = "2.5.1"
|
pest = "2.5.1"
|
||||||
pest_derive = "2.5.1"
|
pest_derive = "2.5.1"
|
||||||
rayon = "1.6.0"
|
rayon = "1.6.0"
|
||||||
|
thiserror = "1.0"
|
||||||
ntest = "0.9.0"
|
ntest = "0.9.0"
|
||||||
|
approx = "0.5.1"
|
||||||
|
num-traits = "0.2"
|
||||||
|
ndarray = "0.15.0"
|
||||||
|
ndarray-rand = "0.14.0"
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ run_linters || exit 1
|
|||||||
for RUNNER in "${RUNNERS[@]}"; do
|
for RUNNER in "${RUNNERS[@]}"; do
|
||||||
echo "Running with $RUNNER..."
|
echo "Running with $RUNNER..."
|
||||||
|
|
||||||
TESTS=("--lib assignment11_grade")
|
TESTS=("--lib assignment11")
|
||||||
if [ $(run_tests) -ne 0 ]; then
|
if [ $(run_tests) -ne 0 ]; then
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ run_linters || exit 1
|
|||||||
for RUNNER in "${RUNNERS[@]}"; do
|
for RUNNER in "${RUNNERS[@]}"; do
|
||||||
echo "Running with $RUNNER..."
|
echo "Running with $RUNNER..."
|
||||||
|
|
||||||
TESTS=("--lib assignment12_grade")
|
TESTS=("--lib assignment11")
|
||||||
if [ $(run_tests) -ne 0 ]; then
|
if [ $(run_tests) -ne 0 ]; then
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -5,22 +5,45 @@
|
|||||||
//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-08.sh` works fine.
|
//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-08.sh` works fine.
|
||||||
//! See `assignment08_grade.rs` and `/scripts/grade-08.sh` for the test script.
|
//! See `assignment08_grade.rs` and `/scripts/grade-08.sh` for the test script.
|
||||||
|
|
||||||
/// Returns an anonymous function that applies the given function `f` for `n` times.
|
/// Repeat
|
||||||
///
|
///
|
||||||
|
/// Returns an anonymous function that applies the given function `f` for `n` times.
|
||||||
/// For instance, `repeat(3, f)(x)` roughly translates to `f(f(f(x)))`.
|
/// For instance, `repeat(3, f)(x)` roughly translates to `f(f(f(x)))`.
|
||||||
|
///
|
||||||
|
/// Refer `test_repeat` in `assignment08_grade.rs` for detailed examples.
|
||||||
pub fn repeat<T, F: FnMut(T) -> T>(n: usize, mut f: F) -> impl FnMut(T) -> T {
|
pub fn repeat<T, F: FnMut(T) -> T>(n: usize, mut f: F) -> impl FnMut(T) -> T {
|
||||||
todo!();
|
todo!();
|
||||||
f // This line has been added to prevent compile error. You can erase this line.
|
f // This line has been added to prevent compile error. You can erase this line.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Funny Map
|
||||||
|
///
|
||||||
/// Applies the given function `f` for `i` times for the `i`-th element of the given vector.
|
/// Applies the given function `f` for `i` times for the `i`-th element of the given vector.
|
||||||
///
|
///
|
||||||
/// For instance, `funny_map(f, [v0, v1, v2, v3])` roughly translates to `[v0, f(v1), f(f(v2)), f(f(f(v3)))]`.
|
/// For instance, `funny_map(f, [v0, v1, v2, v3])` roughly translates to `[v0, f(v1), f(f(v2)), f(f(f(v3)))]`.
|
||||||
|
///
|
||||||
|
/// Refer `test_funny_map` in `assignment08_grade.rs` for detailed examples.
|
||||||
pub fn funny_map<T, F: Fn(T) -> T>(f: F, vs: Vec<T>) -> Vec<T> {
|
pub fn funny_map<T, F: Fn(T) -> T>(f: F, vs: Vec<T>) -> Vec<T> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Count Repeat
|
||||||
|
///
|
||||||
|
/// Returns the number of the elements of the set
|
||||||
|
/// {x, f(x), f(f(x)), f(f(f(x))), ...}.
|
||||||
|
/// You may assume that the answer is finite and small enough.
|
||||||
|
///
|
||||||
|
/// Refer `test_count_repeat` in `assignment08_grade.rs` for detailed examples.
|
||||||
|
pub fn count_repeat<T, F: Fn(T) -> T>(f: F, x: T) -> usize
|
||||||
|
where
|
||||||
|
T: PartialEq + Copy,
|
||||||
|
{
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
/// Either `T1`, or `T2`.
|
/// Either `T1`, or `T2`.
|
||||||
|
///
|
||||||
|
/// Fill out `map` method for this type.
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub enum Either2<T1, T2> {
|
pub enum Either2<T1, T2> {
|
||||||
/// Case 1.
|
/// Case 1.
|
||||||
@@ -39,6 +62,8 @@ impl<T1, T2> Either2<T1, T2> {
|
|||||||
/// Maps the inner value.
|
/// Maps the inner value.
|
||||||
///
|
///
|
||||||
/// If the inner value is case 1, apply `f1`, and if it is case 2, apply `f2`.
|
/// If the inner value is case 1, apply `f1`, and if it is case 2, apply `f2`.
|
||||||
|
///
|
||||||
|
/// Refer `test_either2_map` in `assignment08_grade.rs` for detailed examples.
|
||||||
pub fn map<U1, U2, F1, F2>(self, f1: F1, f2: F2) -> Either2<U1, U2>
|
pub fn map<U1, U2, F1, F2>(self, f1: F1, f2: F2) -> Either2<U1, U2>
|
||||||
where
|
where
|
||||||
F1: FnOnce(T1) -> U1,
|
F1: FnOnce(T1) -> U1,
|
||||||
|
|||||||
@@ -27,4 +27,21 @@ mod test {
|
|||||||
let u2 = Either2::<u32, f32>::Case2 { inner: 43.0 };
|
let u2 = Either2::<u32, f32>::Case2 { inner: 43.0 };
|
||||||
assert_eq!(u2, v2.map(|i| i + 1, |f| f + 1.0));
|
assert_eq!(u2, v2.map(|i| i + 1, |f| f + 1.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_count_repeat() {
|
||||||
|
let inc_mod_100 = |x| (x + 1) % 100;
|
||||||
|
assert_eq!(count_repeat(inc_mod_100, 10), 100);
|
||||||
|
assert_eq!(count_repeat(inc_mod_100, 12345), 101);
|
||||||
|
|
||||||
|
let p_lookup = |n| vec![1, 0, 2, 4, 5, 6, 7, 3][n];
|
||||||
|
assert_eq!(count_repeat(p_lookup, 0), 2);
|
||||||
|
assert_eq!(count_repeat(p_lookup, 1), 2);
|
||||||
|
assert_eq!(count_repeat(p_lookup, 2), 1);
|
||||||
|
assert_eq!(count_repeat(p_lookup, 3), 5);
|
||||||
|
assert_eq!(count_repeat(p_lookup, 4), 5);
|
||||||
|
assert_eq!(count_repeat(p_lookup, 5), 5);
|
||||||
|
assert_eq!(count_repeat(p_lookup, 6), 5);
|
||||||
|
assert_eq!(count_repeat(p_lookup, 7), 5);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
202
src/assignments/assignment11/bst.rs
Normal file
202
src/assignments/assignment11/bst.rs
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
//! Binary Search Tree
|
||||||
|
//!
|
||||||
|
//! Refer `bst_grade.rs` for test cases.
|
||||||
|
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
use std::fmt::Debug;
|
||||||
|
use std::ops::Deref;
|
||||||
|
use std::rc::{Rc, Weak};
|
||||||
|
|
||||||
|
/// Node struct of tree
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct Node<T>
|
||||||
|
where
|
||||||
|
T: Ord,
|
||||||
|
{
|
||||||
|
value: T,
|
||||||
|
parent: Option<Weak<RefCell<Node<T>>>>,
|
||||||
|
left: Option<Rc<RefCell<Node<T>>>>,
|
||||||
|
right: Option<Rc<RefCell<Node<T>>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Node<T>
|
||||||
|
where
|
||||||
|
T: Ord,
|
||||||
|
{
|
||||||
|
fn new(value: T) -> Rc<RefCell<Node<T>>> {
|
||||||
|
Rc::new(RefCell::new(Node {
|
||||||
|
value,
|
||||||
|
parent: None,
|
||||||
|
left: None,
|
||||||
|
right: None,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with_parent(value: T, parent: Weak<RefCell<Node<T>>>) -> Rc<RefCell<Node<T>>> {
|
||||||
|
Rc::new(RefCell::new(Node {
|
||||||
|
value,
|
||||||
|
parent: Some(parent),
|
||||||
|
left: None,
|
||||||
|
right: None,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Minimum node starting from cursor
|
||||||
|
fn min_node(mut cursor: Rc<RefCell<Node<T>>>) -> Rc<RefCell<Node<T>>> {
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Upgraded parent node.
|
||||||
|
/// `None` if the node has no parent.
|
||||||
|
fn parent(&self) -> Option<Rc<RefCell<Node<T>>>> {
|
||||||
|
self.parent.as_ref().and_then(|p| p.upgrade())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Binary Search Tree
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Tree<T>
|
||||||
|
where
|
||||||
|
T: Ord,
|
||||||
|
{
|
||||||
|
root: Option<Rc<RefCell<Node<T>>>>,
|
||||||
|
len: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Ord> Default for Tree<T> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Tree<T>
|
||||||
|
where
|
||||||
|
T: Ord,
|
||||||
|
{
|
||||||
|
/// New tree
|
||||||
|
pub fn new() -> Tree<T> {
|
||||||
|
Tree { root: None, len: 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Length of the tree
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.len
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if the tree is empty.
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.len == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if the tree contains the value.
|
||||||
|
pub fn contains(&self, value: &T) -> bool {
|
||||||
|
if let Some(mut cursor) = self.root.clone() {
|
||||||
|
todo!();
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Insert the value into the tree.
|
||||||
|
/// If there was no equal value in the tree, it returns `true`.
|
||||||
|
/// Otherwise, it returns `false`.
|
||||||
|
pub fn insert(&mut self, value: T) -> bool {
|
||||||
|
self.len += 1;
|
||||||
|
if let Some(mut cursor) = self.root.clone() {
|
||||||
|
todo!();
|
||||||
|
} else {
|
||||||
|
self.root = Some(Node::new(value));
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove the node from the tree.
|
||||||
|
/// Returns the value of the removed node.
|
||||||
|
fn remove_node(&mut self, mut node: Rc<RefCell<Node<T>>>) -> T {
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove the value from the tree.
|
||||||
|
/// If there is an equal value in the tree, it returns `true`.
|
||||||
|
/// Otherwise, it returns `false`.
|
||||||
|
pub fn remove(&mut self, value: &T) -> Option<T> {
|
||||||
|
let res = if let Some(root) = self.root.clone() {
|
||||||
|
let mut cursor = root;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let mut cursor_ref = cursor.deref().borrow_mut();
|
||||||
|
let child = match value.cmp(&cursor_ref.value) {
|
||||||
|
Ordering::Less => cursor_ref.left.clone(),
|
||||||
|
Ordering::Greater => cursor_ref.right.clone(),
|
||||||
|
Ordering::Equal => {
|
||||||
|
drop(cursor_ref);
|
||||||
|
break Some(self.remove_node(cursor));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(child) = child {
|
||||||
|
drop(cursor_ref);
|
||||||
|
cursor = child;
|
||||||
|
} else {
|
||||||
|
break None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
self.len -= res.is_some() as usize;
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Clone for Tree<T>
|
||||||
|
where
|
||||||
|
T: Ord + Clone,
|
||||||
|
{
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Tree {
|
||||||
|
root: self.root.clone(),
|
||||||
|
len: self.len,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// IntoIterator for Tree
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct IntoIter<T>
|
||||||
|
where
|
||||||
|
T: Ord,
|
||||||
|
{
|
||||||
|
tree: Tree<T>,
|
||||||
|
len: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> IntoIterator for Tree<T>
|
||||||
|
where
|
||||||
|
T: Ord,
|
||||||
|
{
|
||||||
|
type Item = T;
|
||||||
|
type IntoIter = IntoIter<T>;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
let len = self.len;
|
||||||
|
IntoIter { tree: self, len }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Iterator for IntoIter<T>
|
||||||
|
where
|
||||||
|
T: Ord,
|
||||||
|
{
|
||||||
|
type Item = T;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
|
(self.len, Some(self.len))
|
||||||
|
}
|
||||||
|
}
|
||||||
53
src/assignments/assignment11/bst_grade.rs
Normal file
53
src/assignments/assignment11/bst_grade.rs
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
//! Test cases for assignment11/bst.rs
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test_bst {
|
||||||
|
use super::super::bst::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn bst_insert_test() {
|
||||||
|
let mut tree = Tree::new();
|
||||||
|
|
||||||
|
let _ = tree.insert(1);
|
||||||
|
let _ = tree.insert(5);
|
||||||
|
let _ = tree.insert(3);
|
||||||
|
let _ = tree.insert(7);
|
||||||
|
|
||||||
|
assert_eq!(tree.into_iter().collect::<Vec<_>>(), vec![1, 3, 5, 7]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn bst_remove_test() {
|
||||||
|
let mut tree = Tree::new();
|
||||||
|
|
||||||
|
let _ = tree.insert(1);
|
||||||
|
let _ = tree.insert(5);
|
||||||
|
let _ = tree.insert(3);
|
||||||
|
let _ = tree.insert(7);
|
||||||
|
let _ = tree.remove(&7);
|
||||||
|
|
||||||
|
assert_eq!(tree.into_iter().collect::<Vec<_>>(), vec![1, 3, 5]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn bst_complex_test() {
|
||||||
|
let mut tree = Tree::new();
|
||||||
|
|
||||||
|
let _ = tree.insert(1);
|
||||||
|
let _ = tree.insert(5);
|
||||||
|
let _ = tree.insert(3);
|
||||||
|
let _ = tree.insert(7);
|
||||||
|
let _ = tree.remove(&7);
|
||||||
|
let _ = tree.insert(7);
|
||||||
|
let _ = tree.insert(6);
|
||||||
|
let _ = tree.insert(8);
|
||||||
|
let _ = tree.remove(&5);
|
||||||
|
let _ = tree.remove(&1);
|
||||||
|
let _ = tree.remove(&3);
|
||||||
|
let _ = tree.remove(&7);
|
||||||
|
let _ = tree.remove(&6);
|
||||||
|
let _ = tree.remove(&8);
|
||||||
|
|
||||||
|
assert_eq!(tree.into_iter().collect::<Vec<_>>(), vec![]);
|
||||||
|
}
|
||||||
|
}
|
||||||
101
src/assignments/assignment11/doubly_linked_list.rs
Normal file
101
src/assignments/assignment11/doubly_linked_list.rs
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
//! Doubly Linked List.
|
||||||
|
//!
|
||||||
|
//! Refer `doubly_linked_list_grade.rs` for test cases.
|
||||||
|
|
||||||
|
use std::{cell::RefCell, fmt::Debug, rc::Rc};
|
||||||
|
|
||||||
|
type Link<T> = Option<Rc<RefCell<Node<T>>>>;
|
||||||
|
|
||||||
|
/// Node of a doubly-linked list.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Node<T: Debug + Clone> {
|
||||||
|
/// Value of current node.
|
||||||
|
value: RefCell<T>,
|
||||||
|
|
||||||
|
/// Pointer to the next node. If it is `None`, there is no next node.
|
||||||
|
next: Link<T>,
|
||||||
|
|
||||||
|
/// Pointer to the previous node. If it is `None`, there is no previous node.
|
||||||
|
prev: Link<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Debug + Clone> Node<T> {
|
||||||
|
/// Creates a new node.
|
||||||
|
fn new(value: T) -> Self {
|
||||||
|
Self {
|
||||||
|
value: RefCell::new(value),
|
||||||
|
next: None,
|
||||||
|
prev: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Fetch the value contained in node
|
||||||
|
pub fn get(&self) -> T {
|
||||||
|
self.value.borrow().clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Replace the data contained in the node
|
||||||
|
pub fn replace(&self, new_value: T) -> T {
|
||||||
|
self.value.replace(new_value)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Fetch previous node
|
||||||
|
pub fn prev(&self) -> Link<T> {
|
||||||
|
self.prev.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Fetch next node
|
||||||
|
pub fn next(&self) -> Link<T> {
|
||||||
|
self.next.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A doubly-linked list.
|
||||||
|
#[derive(Default, Debug)]
|
||||||
|
pub struct DoublyLinkedList<T: Debug + Clone> {
|
||||||
|
/// Head node of the list. If it is `None`, the list is empty.
|
||||||
|
head: Link<T>,
|
||||||
|
|
||||||
|
/// Tail node of the list. If it is `None`, the list is empty.
|
||||||
|
tail: Link<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Debug + Clone> DoublyLinkedList<T> {
|
||||||
|
/// Creates a new list.
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
head: None,
|
||||||
|
tail: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds the given node to the front of the list.
|
||||||
|
pub fn push_front(&mut self, value: T) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds the given node to the back of the list.
|
||||||
|
pub fn push_back(&mut self, value: T) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Removes and returns the node at the front of the list.
|
||||||
|
pub fn pop_front(&mut self) -> Option<T> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Removes and returns the node at the back of the list.
|
||||||
|
pub fn pop_back(&mut self) -> Option<T> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Debug + Clone> Drop for DoublyLinkedList<T> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
while let Some(node) = self.head.take() {
|
||||||
|
let _ = node.borrow_mut().prev.take();
|
||||||
|
self.head = node.borrow_mut().next.take();
|
||||||
|
}
|
||||||
|
let _unused = self.tail.take();
|
||||||
|
}
|
||||||
|
}
|
||||||
43
src/assignments/assignment11/doubly_linked_list_grade.rs
Normal file
43
src/assignments/assignment11/doubly_linked_list_grade.rs
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
//! Test cases for assignment11/doubly_linked_list.rs
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test_doubly_linked_list {
|
||||||
|
use super::super::doubly_linked_list::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_works() {
|
||||||
|
let mut list = DoublyLinkedList::new();
|
||||||
|
|
||||||
|
list.push_back(3);
|
||||||
|
list.push_back(4);
|
||||||
|
assert_eq!(list.pop_front(), Some(3));
|
||||||
|
|
||||||
|
list.push_front(5);
|
||||||
|
assert_eq!(list.pop_back(), Some(4));
|
||||||
|
assert_eq!(list.pop_back(), Some(5));
|
||||||
|
assert_eq!(list.pop_back(), None);
|
||||||
|
assert_eq!(list.pop_front(), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_can_push_back() {
|
||||||
|
let mut list = DoublyLinkedList::new();
|
||||||
|
assert_eq!(list.pop_back(), None);
|
||||||
|
|
||||||
|
list.push_back(3);
|
||||||
|
list.push_back(4);
|
||||||
|
list.push_back(5);
|
||||||
|
assert_eq!(list.pop_back(), Some(5));
|
||||||
|
|
||||||
|
list.push_back(6);
|
||||||
|
list.push_back(7);
|
||||||
|
assert_eq!(list.pop_back(), Some(7));
|
||||||
|
assert_eq!(list.pop_back(), Some(6));
|
||||||
|
assert_eq!(list.pop_back(), Some(4));
|
||||||
|
assert_eq!(list.pop_back(), Some(3));
|
||||||
|
|
||||||
|
list.push_back(2);
|
||||||
|
assert_eq!(list.pop_back(), Some(2));
|
||||||
|
assert_eq!(list.pop_back(), None);
|
||||||
|
}
|
||||||
|
}
|
||||||
93
src/assignments/assignment11/graph.rs
Normal file
93
src/assignments/assignment11/graph.rs
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
//! A small graph library.
|
||||||
|
//!
|
||||||
|
//! A node has a i32 value and (directed) edges to other nodes. A node does not have multiple edges
|
||||||
|
//! to the same node. Nodes are not associated with a particular domain, and users can freely
|
||||||
|
//! create nodes however they like. However, after a node is created, it can be added to a
|
||||||
|
//! `SubGraph`, which form a subgraph of the graph of all nodes. A node can be added to multiple
|
||||||
|
//! subgraphs. `SubGraph` has a method to check if the it has a cycle.
|
||||||
|
//!
|
||||||
|
//! The goal of this assignment is to learn how to deal with inherently shared mutable data in
|
||||||
|
//! Rust. Design the types and fill in the `todo!()`s in methods. There are several possible
|
||||||
|
//! approaches to this problem and you may import anything from the std library accordingly.
|
||||||
|
//!
|
||||||
|
//! Refer `graph_grade.rs` for test cases.
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Debug)]
|
||||||
|
enum VisitStatus {
|
||||||
|
Unvisited,
|
||||||
|
Visiting,
|
||||||
|
Visited,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Handle to a graph node.
|
||||||
|
/// `NodeHandle` should implement `Clone`, which clones the handle without cloning the underlying
|
||||||
|
/// node. That is, there can be multiple handles to the same node.
|
||||||
|
/// The user can access the node through a handle if it does not violate Rust's aliasing rules.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct NodeHandle;
|
||||||
|
|
||||||
|
/// Error type for graph operations.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct GraphError;
|
||||||
|
|
||||||
|
/// Subgraph
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct SubGraph;
|
||||||
|
|
||||||
|
impl NodeHandle {
|
||||||
|
/// Creates a node and returns the handle to it.
|
||||||
|
pub fn new(value: i32) -> Self {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds an edge to `to`.
|
||||||
|
/// If the modification cannot be done, e.g. because of aliasing issues, returns `Err(GraphError)`.
|
||||||
|
/// Returns `Ok(true)` if the edge is successfully added.
|
||||||
|
/// Returns `Ok(false)` if an edge to `to` already exits.
|
||||||
|
pub fn add_edge(&self, to: NodeHandle) -> Result<bool, GraphError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Removes the edge to `to`.
|
||||||
|
/// If the modification cannot be done, e.g. because of aliasing issues, returns `Err(GraphError)`.
|
||||||
|
/// Returns `Ok(true)` if the edge is successfully removed.
|
||||||
|
/// Returns `Ok(false)` if an edge to `to` does not exist.
|
||||||
|
pub fn remove_edge(&self, to: &NodeHandle) -> Result<bool, GraphError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Removes all edges.
|
||||||
|
/// If the modification cannot be done, e.g. because of aliasing issues, returns `Err(GraphError)`.
|
||||||
|
pub fn clear_edges(&self) -> Result<(), GraphError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for SubGraph {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SubGraph {
|
||||||
|
/// Creates a new subgraph.
|
||||||
|
pub fn new() -> Self {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds a node to the subgraph. Returns true iff the node is newly added.
|
||||||
|
pub fn add_node(&mut self, node: NodeHandle) -> bool {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds a node to the subgraph. Returns true iff the node is successfully removed.
|
||||||
|
pub fn remove_node(&mut self, node: &NodeHandle) -> bool {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true iff the subgraph contains a cycle. Nodes that do not belong to this subgraph
|
||||||
|
/// are ignored. See https://en.wikipedia.org/wiki/Cycle_(graph_theory) for an algorithm.
|
||||||
|
pub fn detect_cycle(&self) -> bool {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
63
src/assignments/assignment11/graph_grade.rs
Normal file
63
src/assignments/assignment11/graph_grade.rs
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
//! Test cases for assignment11/graph.rs
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test_graph {
|
||||||
|
use super::super::graph::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_graph() {
|
||||||
|
let mut nodes = (0..6).map(NodeHandle::new).collect::<Vec<_>>();
|
||||||
|
let edges = [
|
||||||
|
(0, 1),
|
||||||
|
(0, 3),
|
||||||
|
(1, 4),
|
||||||
|
(2, 4),
|
||||||
|
(2, 5),
|
||||||
|
(3, 1),
|
||||||
|
(4, 3),
|
||||||
|
(5, 5),
|
||||||
|
];
|
||||||
|
|
||||||
|
for (from, to) in edges {
|
||||||
|
assert!(nodes[from].add_edge(nodes[to].clone()).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut graph1 = SubGraph::new();
|
||||||
|
for n in 0..6 {
|
||||||
|
assert!(graph1.add_node(nodes[n].clone()));
|
||||||
|
}
|
||||||
|
assert!(graph1.detect_cycle());
|
||||||
|
assert!(!graph1.add_node(nodes[0].clone()));
|
||||||
|
|
||||||
|
let mut graph2 = SubGraph::new();
|
||||||
|
for n in [0, 1, 3] {
|
||||||
|
assert!(graph2.add_node(nodes[n].clone()));
|
||||||
|
}
|
||||||
|
assert!(!graph2.detect_cycle());
|
||||||
|
|
||||||
|
assert!(graph2.add_node(nodes[4].clone()));
|
||||||
|
assert!(graph2.detect_cycle());
|
||||||
|
|
||||||
|
assert!(nodes[4].remove_edge(&nodes[3]).unwrap());
|
||||||
|
assert!(!graph2.detect_cycle());
|
||||||
|
|
||||||
|
let mut graph3 = SubGraph::new();
|
||||||
|
for n in [0, 1, 2, 3] {
|
||||||
|
assert!(graph3.add_node(nodes[n].clone()));
|
||||||
|
}
|
||||||
|
assert!(!graph3.detect_cycle());
|
||||||
|
|
||||||
|
let more_edges = [(1, 2), (2, 3)];
|
||||||
|
for (from, to) in more_edges {
|
||||||
|
assert!(nodes[from].add_edge(nodes[to].clone()).unwrap());
|
||||||
|
}
|
||||||
|
assert!(graph3.detect_cycle());
|
||||||
|
|
||||||
|
assert!(graph3.remove_node(&nodes[2]));
|
||||||
|
assert!(!graph3.detect_cycle());
|
||||||
|
|
||||||
|
for n in nodes {
|
||||||
|
n.clear_edges().unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
//! Singly linked list.
|
//! Singly linked list.
|
||||||
//!
|
//!
|
||||||
//! Consult <https://doc.rust-lang.org/book/ch15-01-box.html>.
|
//! Hint: Consult <https://doc.rust-lang.org/book/ch15-01-box.html>.
|
||||||
|
//!
|
||||||
|
//! Refer `linked_list_grade.rs` for test cases.
|
||||||
|
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
|||||||
27
src/assignments/assignment11/linked_list_grade.rs
Normal file
27
src/assignments/assignment11/linked_list_grade.rs
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
//! Test cases for assignment11/linked_list.rs
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test_linked_list {
|
||||||
|
use super::super::linked_list::*;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
struct V(usize);
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_linked_list() {
|
||||||
|
let mut list = SinglyLinkedList::new();
|
||||||
|
list.push_back(V(3));
|
||||||
|
list.push_front(V(2));
|
||||||
|
list.push_back(V(4));
|
||||||
|
list.push_front(V(1));
|
||||||
|
list.push_back(V(5));
|
||||||
|
|
||||||
|
assert_eq!(list.pop_front(), Some(V(1)));
|
||||||
|
assert_eq!(list.pop_back(), Some(V(5)));
|
||||||
|
assert_eq!(list.pop_front(), Some(V(2)));
|
||||||
|
assert_eq!(list.pop_back(), Some(V(4)));
|
||||||
|
assert_eq!(list.pop_front(), Some(V(3)));
|
||||||
|
assert_eq!(list.pop_back(), None);
|
||||||
|
assert_eq!(list.pop_front(), None);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
//! Mock storage.
|
//! Mock storage.
|
||||||
//!
|
//!
|
||||||
//! Consult <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html#a-use-case-for-interior-mutability-mock-objects>.
|
//! Hint: Consult <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html#a-use-case-for-interior-mutability-mock-objects>.
|
||||||
|
//!
|
||||||
|
//! Refer `mock_storage_grade.rs` for test cases.
|
||||||
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|||||||
31
src/assignments/assignment11/mock_storage_grade.rs
Normal file
31
src/assignments/assignment11/mock_storage_grade.rs
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
//! Test cases for assignment11/mock_storage.rs
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test_mock_storage {
|
||||||
|
use super::super::mock_storage::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_mock_storage() {
|
||||||
|
let mock_storage = MockStorage::new(100);
|
||||||
|
|
||||||
|
let uploader1 = FileUploader::new(&mock_storage);
|
||||||
|
let uploader2 = FileUploader::new(&mock_storage);
|
||||||
|
|
||||||
|
let usage_analyzer = UsageAnalyzer::new(&mock_storage, 0.75);
|
||||||
|
|
||||||
|
assert!(uploader1.upload("file1.txt", 20).is_ok());
|
||||||
|
assert!(usage_analyzer.is_usage_under_bound());
|
||||||
|
|
||||||
|
assert!(uploader2.upload("file2.txt", 30).is_ok());
|
||||||
|
assert!(usage_analyzer.is_usage_under_bound());
|
||||||
|
|
||||||
|
assert!(uploader1.upload("file3.txt", 40).is_ok());
|
||||||
|
assert!(!usage_analyzer.is_usage_under_bound());
|
||||||
|
|
||||||
|
assert_eq!(uploader2.upload("file4.txt", 50), Err(40));
|
||||||
|
assert!(!usage_analyzer.is_usage_under_bound());
|
||||||
|
|
||||||
|
assert!(uploader1.upload("file3.txt", 10).is_ok());
|
||||||
|
assert!(usage_analyzer.is_usage_under_bound());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,16 @@
|
|||||||
//! See `assignment11_grade.rs` and `/scripts/grade-11.sh` for the test script.
|
//! See `assignment11_grade.rs` and `/scripts/grade-11.sh` for the test script.
|
||||||
//! Run `/scripts/prepare-submissions.sh` and submit `/target/assignment11.zip` to <https://gg.kaist.ac.kr>.
|
//! Run `/scripts/prepare-submissions.sh` and submit `/target/assignment11.zip` to <https://gg.kaist.ac.kr>.
|
||||||
|
|
||||||
|
pub mod bst;
|
||||||
|
pub mod bst_grade;
|
||||||
|
pub mod doubly_linked_list;
|
||||||
|
pub mod doubly_linked_list_grade;
|
||||||
|
pub mod graph;
|
||||||
|
pub mod graph_grade;
|
||||||
pub mod linked_list;
|
pub mod linked_list;
|
||||||
pub mod mock_storage;
|
pub mod mock_storage;
|
||||||
|
pub mod mock_storage_grade;
|
||||||
|
pub mod turing_machine;
|
||||||
|
pub mod turing_machine_grade;
|
||||||
pub mod tv_room;
|
pub mod tv_room;
|
||||||
|
pub mod tv_room_grade;
|
||||||
|
|||||||
139
src/assignments/assignment11/turing_machine.rs
Normal file
139
src/assignments/assignment11/turing_machine.rs
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
//! Simple Turing machien emulator
|
||||||
|
//!
|
||||||
|
//! Simple One-head, One-tape turing machine
|
||||||
|
//! See <https://en.wikipedia.org/wiki/Turing_machine> that describes what turing machine is.
|
||||||
|
//! See `test_turing_machine` module in `assignment11_grade.rs` for examples.
|
||||||
|
//!
|
||||||
|
//! Goal: To be accustomed with `RefCell`, `HashMap`
|
||||||
|
//!
|
||||||
|
//! Refer `turing_machine.rs` for test cases.
|
||||||
|
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::fmt::{self, Formatter};
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
/// Error type for Turing machine
|
||||||
|
/// <https://google.github.io/comprehensive-rust/error-handling/deriving-error-enums.html>
|
||||||
|
#[derive(Debug, Error, PartialEq, Eq)]
|
||||||
|
pub enum TuringMachineError {
|
||||||
|
/// Invalid movement
|
||||||
|
/// You can't move left from the leftmost location
|
||||||
|
/// or move right from the rightmost location.
|
||||||
|
#[error("Invalid movement")]
|
||||||
|
InvalidMovement,
|
||||||
|
|
||||||
|
/// Exceeded maximum steps
|
||||||
|
#[error("Exceeded maximum steps")]
|
||||||
|
ExceedMaxSteps,
|
||||||
|
|
||||||
|
/// Invalid state or value
|
||||||
|
/// Occurs when you cannot find instruction for the current state and value
|
||||||
|
#[error("Invalid state or value")]
|
||||||
|
InvalidStateOrValue,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Turing Machine implementation
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct TuringMachine<TMState, TMValue>
|
||||||
|
where
|
||||||
|
TMState: Default + Eq + PartialEq + std::hash::Hash + Clone,
|
||||||
|
TMValue: Eq + PartialEq + std::hash::Hash + Clone,
|
||||||
|
{
|
||||||
|
/// Number of steps taken by the Turing machine
|
||||||
|
pub steps: RefCell<usize>,
|
||||||
|
|
||||||
|
/// Table of instructions for the Turing machine
|
||||||
|
pub table: HashMap<(TMState, TMValue), (TMState, Move, TMValue)>,
|
||||||
|
|
||||||
|
/// Tape of the Turing machine. Finite length
|
||||||
|
pub tape: Vec<RefCell<TMValue>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implementation of the movement instructions of the head of the tape.
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
|
pub enum Move {
|
||||||
|
/// Move Left
|
||||||
|
L,
|
||||||
|
/// Move Right
|
||||||
|
R,
|
||||||
|
/// Don't move
|
||||||
|
N,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Cursor for Turing machine
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Cursor<'a, TMState, TMValue>
|
||||||
|
where
|
||||||
|
TMState: Default + Eq + PartialEq + std::hash::Hash + Clone,
|
||||||
|
TMValue: Eq + PartialEq + std::hash::Hash + Clone,
|
||||||
|
{
|
||||||
|
// Turing mahcine
|
||||||
|
tm: &'a TuringMachine<TMState, TMValue>,
|
||||||
|
// Index of the tape
|
||||||
|
index: usize,
|
||||||
|
// Current state of the Turing machine
|
||||||
|
state: TMState,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, TMState, TMValue> Cursor<'a, TMState, TMValue>
|
||||||
|
where
|
||||||
|
TMState: Default + Eq + PartialEq + std::hash::Hash + Clone,
|
||||||
|
TMValue: Eq + PartialEq + std::hash::Hash + Clone,
|
||||||
|
{
|
||||||
|
/// Generate new cursor
|
||||||
|
pub fn new(tm: &'a TuringMachine<TMState, TMValue>, state: TMState, index: usize) -> Self {
|
||||||
|
Cursor { tm, index, state }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run the Turing machine until it halts (if it halts). Print every step of that.
|
||||||
|
pub fn run(&mut self, max_step: usize) -> Result<(TMValue, usize), TuringMachineError> {
|
||||||
|
let mut steps = self.tm.steps.borrow_mut();
|
||||||
|
while self.state != TMState::default() {
|
||||||
|
*steps += 1;
|
||||||
|
if *steps > max_step {
|
||||||
|
return Err(TuringMachineError::ExceedMaxSteps);
|
||||||
|
}
|
||||||
|
self.step()?;
|
||||||
|
// println!("{}", self);
|
||||||
|
}
|
||||||
|
Ok((self.get(), *steps))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set tape value at the current index with `value`
|
||||||
|
/// You may need this function for `mov` function
|
||||||
|
fn set(&mut self, value: TMValue) -> TMValue {
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Step the Turing machine
|
||||||
|
/// Look at the `run` function to see how this function is used.
|
||||||
|
fn step(&mut self) -> Result<(), TuringMachineError> {
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Move the cursor while setting the value of the current index
|
||||||
|
fn mov(&mut self, new_value: TMValue, movement: &Move) -> Result<(), TuringMachineError> {
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the value of the current index
|
||||||
|
/// Look at the `run` function to see how this function is used.
|
||||||
|
fn get(&self) -> TMValue {
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<TMState, TMValue> TuringMachine<TMState, TMValue>
|
||||||
|
where
|
||||||
|
TMState: Default + Eq + PartialEq + std::hash::Hash + Clone,
|
||||||
|
TMValue: Eq + PartialEq + std::hash::Hash + Clone,
|
||||||
|
{
|
||||||
|
/// Generate new Turing machine
|
||||||
|
pub fn new(
|
||||||
|
table: HashMap<(TMState, TMValue), (TMState, Move, TMValue)>,
|
||||||
|
tape: Vec<RefCell<TMValue>>,
|
||||||
|
) -> Self {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
309
src/assignments/assignment11/turing_machine_grade.rs
Normal file
309
src/assignments/assignment11/turing_machine_grade.rs
Normal file
@@ -0,0 +1,309 @@
|
|||||||
|
//! Test cases for assignment11/turing_machine.rs
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test_turing_machine {
|
||||||
|
use super::super::turing_machine::*;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_invalid_movement() {
|
||||||
|
/// Cell value of the tape
|
||||||
|
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
|
||||||
|
enum TMValue {
|
||||||
|
/// Zero
|
||||||
|
Zero,
|
||||||
|
|
||||||
|
/// One
|
||||||
|
One,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// State for Turing machine
|
||||||
|
/// TODO: Modify this so that users can implement their own state
|
||||||
|
#[derive(Default, Debug, Eq, PartialEq, Hash, Clone)]
|
||||||
|
enum TMState {
|
||||||
|
/// Halt
|
||||||
|
#[default]
|
||||||
|
Halt,
|
||||||
|
|
||||||
|
/// A
|
||||||
|
A,
|
||||||
|
|
||||||
|
/// B
|
||||||
|
B,
|
||||||
|
}
|
||||||
|
|
||||||
|
let tape: Vec<RefCell<TMValue>> = vec![
|
||||||
|
TMValue::One,
|
||||||
|
TMValue::Zero,
|
||||||
|
TMValue::One,
|
||||||
|
TMValue::One,
|
||||||
|
TMValue::One,
|
||||||
|
TMValue::Zero,
|
||||||
|
TMValue::One,
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
.map(|x| RefCell::new(x))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let instr = HashMap::from([
|
||||||
|
(
|
||||||
|
(TMState::A, TMValue::Zero),
|
||||||
|
(TMState::B, Move::R, TMValue::One),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
(TMState::A, TMValue::One),
|
||||||
|
(TMState::B, Move::L, TMValue::Zero),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
(TMState::B, TMValue::Zero),
|
||||||
|
(TMState::A, Move::L, TMValue::One),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
(TMState::B, TMValue::One),
|
||||||
|
(TMState::A, Move::R, TMValue::Zero),
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
|
||||||
|
let mut tm = TuringMachine::new(instr, tape);
|
||||||
|
let mut cursor = Cursor::new(&tm, TMState::A, 0);
|
||||||
|
|
||||||
|
let result = cursor.run(1000);
|
||||||
|
assert_eq!(result, Err(TuringMachineError::InvalidMovement));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_write_15_fail_move() {
|
||||||
|
/// Cell value of the tape
|
||||||
|
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
|
||||||
|
enum TMValue {
|
||||||
|
/// Zero
|
||||||
|
Zero,
|
||||||
|
|
||||||
|
/// One
|
||||||
|
One,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// State for Turing machine
|
||||||
|
/// TODO: Modify this so that users can implement their own state
|
||||||
|
#[derive(Default, Debug, Eq, PartialEq, Hash, Clone)]
|
||||||
|
enum TMState {
|
||||||
|
/// Halt
|
||||||
|
#[default]
|
||||||
|
Halt,
|
||||||
|
|
||||||
|
/// A
|
||||||
|
A,
|
||||||
|
|
||||||
|
/// B
|
||||||
|
B,
|
||||||
|
}
|
||||||
|
|
||||||
|
let tape: Vec<RefCell<TMValue>> = vec![TMValue::Zero; 10]
|
||||||
|
.into_iter()
|
||||||
|
.map(|x| RefCell::new(x))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let instr = HashMap::from([
|
||||||
|
(
|
||||||
|
(TMState::A, TMValue::Zero),
|
||||||
|
(TMState::B, Move::R, TMValue::One),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
(TMState::A, TMValue::One),
|
||||||
|
(TMState::B, Move::L, TMValue::One),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
(TMState::B, TMValue::Zero),
|
||||||
|
(TMState::A, Move::L, TMValue::One),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
(TMState::B, TMValue::One),
|
||||||
|
(TMState::Halt, Move::R, TMValue::One),
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
|
||||||
|
let mut tm = TuringMachine::new(instr, tape);
|
||||||
|
let mut cursor = Cursor::new(&tm, TMState::A, 0);
|
||||||
|
|
||||||
|
let result = cursor.run(1000);
|
||||||
|
assert_eq!(result, Err(TuringMachineError::InvalidMovement));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_write_15_pass() {
|
||||||
|
/// Cell value of the tape
|
||||||
|
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
|
||||||
|
enum TMValue {
|
||||||
|
/// Zero
|
||||||
|
Zero,
|
||||||
|
|
||||||
|
/// One
|
||||||
|
One,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// State for Turing machine
|
||||||
|
/// TODO: Modify this so that users can implement their own state
|
||||||
|
#[derive(Default, Debug, Eq, PartialEq, Hash, Clone)]
|
||||||
|
enum TMState {
|
||||||
|
/// Halt
|
||||||
|
#[default]
|
||||||
|
Halt,
|
||||||
|
|
||||||
|
/// A
|
||||||
|
A,
|
||||||
|
|
||||||
|
/// B
|
||||||
|
B,
|
||||||
|
}
|
||||||
|
|
||||||
|
let tape: Vec<RefCell<TMValue>> = vec![TMValue::Zero; 10]
|
||||||
|
.into_iter()
|
||||||
|
.map(|x| RefCell::new(x))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let instr = HashMap::from([
|
||||||
|
(
|
||||||
|
(TMState::A, TMValue::Zero),
|
||||||
|
(TMState::B, Move::R, TMValue::One),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
(TMState::A, TMValue::One),
|
||||||
|
(TMState::B, Move::L, TMValue::One),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
(TMState::B, TMValue::Zero),
|
||||||
|
(TMState::A, Move::L, TMValue::One),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
(TMState::B, TMValue::One),
|
||||||
|
(TMState::Halt, Move::R, TMValue::One),
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
|
||||||
|
let mut tm = TuringMachine::new(instr, tape);
|
||||||
|
let mut cursor = Cursor::new(&tm, TMState::A, 2);
|
||||||
|
|
||||||
|
let result = cursor.run(1000);
|
||||||
|
for (idx, val) in tm.tape.iter().enumerate() {
|
||||||
|
if idx < 4 {
|
||||||
|
assert_eq!(*val.borrow(), TMValue::One);
|
||||||
|
} else {
|
||||||
|
assert_eq!(*val.borrow(), TMValue::Zero);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_write_zero_ones_fail_step() {
|
||||||
|
/// Cell value of the tape
|
||||||
|
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
|
||||||
|
enum TMValue {
|
||||||
|
/// Empty
|
||||||
|
Empty,
|
||||||
|
|
||||||
|
/// Zero
|
||||||
|
Zero,
|
||||||
|
|
||||||
|
/// One
|
||||||
|
One,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// State for Turing machine
|
||||||
|
/// TODO: Modify this so that users can implement their own state
|
||||||
|
#[derive(Default, Debug, Eq, PartialEq, Hash, Clone)]
|
||||||
|
enum TMState {
|
||||||
|
/// Halt
|
||||||
|
#[default]
|
||||||
|
Halt,
|
||||||
|
|
||||||
|
/// A
|
||||||
|
A,
|
||||||
|
|
||||||
|
/// B
|
||||||
|
B,
|
||||||
|
}
|
||||||
|
|
||||||
|
let tape: Vec<RefCell<TMValue>> = vec![TMValue::Empty; 100]
|
||||||
|
.into_iter()
|
||||||
|
.map(|x| RefCell::new(x))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let instr = HashMap::from([
|
||||||
|
(
|
||||||
|
(TMState::A, TMValue::Empty),
|
||||||
|
(TMState::B, Move::R, TMValue::Zero),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
(TMState::B, TMValue::Empty),
|
||||||
|
(TMState::A, Move::R, TMValue::One),
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
|
||||||
|
let mut tm = TuringMachine::new(instr, tape);
|
||||||
|
let mut cursor = Cursor::new(&tm, TMState::A, 0);
|
||||||
|
|
||||||
|
let result = cursor.run(10);
|
||||||
|
assert_eq!(result, Err(TuringMachineError::ExceedMaxSteps));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_write_zero_ones() {
|
||||||
|
/// Cell value of the tape
|
||||||
|
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
|
||||||
|
enum TMValue {
|
||||||
|
/// Empty
|
||||||
|
Empty,
|
||||||
|
|
||||||
|
/// Zero
|
||||||
|
Zero,
|
||||||
|
|
||||||
|
/// One
|
||||||
|
One,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// State for Turing machine
|
||||||
|
/// TODO: Modify this so that users can implement their own state
|
||||||
|
#[derive(Default, Debug, Eq, PartialEq, Hash, Clone)]
|
||||||
|
enum TMState {
|
||||||
|
/// Halt
|
||||||
|
#[default]
|
||||||
|
Halt,
|
||||||
|
|
||||||
|
/// A
|
||||||
|
A,
|
||||||
|
|
||||||
|
/// B
|
||||||
|
B,
|
||||||
|
}
|
||||||
|
|
||||||
|
let tape: Vec<RefCell<TMValue>> = vec![TMValue::Empty; 100]
|
||||||
|
.into_iter()
|
||||||
|
.map(|x| RefCell::new(x))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let instr = HashMap::from([
|
||||||
|
(
|
||||||
|
(TMState::A, TMValue::Empty),
|
||||||
|
(TMState::B, Move::R, TMValue::Zero),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
(TMState::B, TMValue::Empty),
|
||||||
|
(TMState::A, Move::R, TMValue::One),
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
|
||||||
|
let mut tm = TuringMachine::new(instr, tape);
|
||||||
|
let mut cursor = Cursor::new(&tm, TMState::A, 0);
|
||||||
|
|
||||||
|
let result = cursor.run(1000);
|
||||||
|
assert_eq!(result, Err(TuringMachineError::InvalidMovement));
|
||||||
|
for (idx, val) in tm.tape.iter().enumerate() {
|
||||||
|
if idx % 2 == 0 {
|
||||||
|
assert_eq!(*val.borrow(), TMValue::Zero);
|
||||||
|
} else {
|
||||||
|
assert_eq!(*val.borrow(), TMValue::One);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,6 +15,8 @@
|
|||||||
//! Consult the following documentations:
|
//! Consult the following documentations:
|
||||||
//! - <https://doc.rust-lang.org/book/ch15-04-rc.html#rct-the-reference-counted-smart-pointer>
|
//! - <https://doc.rust-lang.org/book/ch15-04-rc.html#rct-the-reference-counted-smart-pointer>
|
||||||
//! - <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html#having-multiple-owners-of-mutable-data-by-combining-rct-and-refcellt>
|
//! - <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html#having-multiple-owners-of-mutable-data-by-combining-rct-and-refcellt>
|
||||||
|
//!
|
||||||
|
//! Refer `tv_room_grade.rs` for test cases.
|
||||||
|
|
||||||
use std::{cell::RefCell, rc::Rc};
|
use std::{cell::RefCell, rc::Rc};
|
||||||
|
|
||||||
|
|||||||
32
src/assignments/assignment11/tv_room_grade.rs
Normal file
32
src/assignments/assignment11/tv_room_grade.rs
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
//! Test cases for assignment11/tv_room.rs
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test_tv_room {
|
||||||
|
use super::super::tv_room::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_tv_room() {
|
||||||
|
let tv_room = TVRoom::new();
|
||||||
|
assert!(!tv_room.is_opened());
|
||||||
|
|
||||||
|
// Turn on and add new guests.
|
||||||
|
let manager = tv_room.open().unwrap();
|
||||||
|
assert!(tv_room.is_opened());
|
||||||
|
let guest1 = manager.new_guest();
|
||||||
|
let guest2 = manager.new_guest();
|
||||||
|
drop(manager);
|
||||||
|
drop(guest1);
|
||||||
|
assert!(tv_room.open().is_none());
|
||||||
|
drop(guest2);
|
||||||
|
assert!(!tv_room.is_opened());
|
||||||
|
|
||||||
|
// Turn on and add new guests.
|
||||||
|
let manager = tv_room.open().unwrap();
|
||||||
|
assert!(tv_room.is_opened());
|
||||||
|
let guest3 = manager.new_guest();
|
||||||
|
drop(guest3);
|
||||||
|
assert!(tv_room.is_opened());
|
||||||
|
drop(manager);
|
||||||
|
assert!(!tv_room.is_opened());
|
||||||
|
}
|
||||||
|
}
|
||||||
52
src/assignments/assignment12/card.rs
Normal file
52
src/assignments/assignment12/card.rs
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
//! Flipping card game.
|
||||||
|
//!
|
||||||
|
//! For this assignment, you have to see `play` function in `card_grade.rs` file.
|
||||||
|
//! Multiple threads will be created and they will run as enemy bots(`bot_threads`).
|
||||||
|
//! Strategy of the enemy bots is implemented in the closure of the `thread::spawn` function.
|
||||||
|
//! Your goal is to beat them so that there are more white cards than blue cards in the ground.
|
||||||
|
//! Write your strategy in the `flip_card_strategy` function of the `Player` struct.
|
||||||
|
//!
|
||||||
|
//! Have fun!
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
sync::{Arc, Mutex},
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Color represents the color of the card.
|
||||||
|
/// The color of a card can be either Blue or White.
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
pub enum Color {
|
||||||
|
/// blue
|
||||||
|
Blue,
|
||||||
|
|
||||||
|
/// white
|
||||||
|
White,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Player struct represents a player in the card game.
|
||||||
|
/// Each player has a memory which is represented as a HashMap.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Player {
|
||||||
|
memory: HashMap<isize, isize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Player {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Player {
|
||||||
|
/// Creates a new player with an empty memory.
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
memory: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This function should return the index of the card to flip and the color to change to.
|
||||||
|
pub fn flip_card_strategy(&mut self) -> (usize, Color) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
141
src/assignments/assignment12/card_grade.rs
Normal file
141
src/assignments/assignment12/card_grade.rs
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
//! Test cases for assignment12/card.rs
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test_card {
|
||||||
|
use super::super::card::*;
|
||||||
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
use std::sync::{Arc, Barrier, Mutex};
|
||||||
|
use std::thread;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
const NUM_CARDS: usize = 10_000;
|
||||||
|
const DURATION: u64 = 1;
|
||||||
|
const NUM_ENEMIES: usize = 100;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
struct Card {
|
||||||
|
color: Arc<Mutex<Color>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Card {
|
||||||
|
fn new() -> Self {
|
||||||
|
Card {
|
||||||
|
color: Arc::new(Mutex::new(Color::Blue)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flip(&self, new_color: Color) {
|
||||||
|
let mut color = self.color.lock().unwrap();
|
||||||
|
*color = new_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_color(&self) -> Color {
|
||||||
|
let color = self.color.lock().unwrap();
|
||||||
|
*color
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
struct Ground {
|
||||||
|
cards: Vec<Card>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ground {
|
||||||
|
fn new() -> Self {
|
||||||
|
let cards: Vec<_> = (0..NUM_CARDS).map(|_| Card::new()).collect();
|
||||||
|
Ground { cards }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flip_card(&self, idx: usize, color: Color) {
|
||||||
|
self.cards[idx % NUM_CARDS].flip(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_card_color(&self, idx: usize) -> Color {
|
||||||
|
self.cards[idx % NUM_CARDS].get_color()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn play() {
|
||||||
|
let ground = Ground::new();
|
||||||
|
let barrier = Arc::new(Barrier::new(
|
||||||
|
NUM_ENEMIES + 1 /*Player*/ + 1, /*Referee*/
|
||||||
|
));
|
||||||
|
let playing = Arc::new(AtomicBool::new(true));
|
||||||
|
|
||||||
|
// Create a thread for the student's strategy
|
||||||
|
let mut player = Player::new();
|
||||||
|
let player_thread = {
|
||||||
|
let ground = ground.clone();
|
||||||
|
let barrier = barrier.clone();
|
||||||
|
let playing = playing.clone();
|
||||||
|
|
||||||
|
// The player's strategy thread
|
||||||
|
thread::spawn(move || {
|
||||||
|
// Get, Set, Ready, Go!
|
||||||
|
let _ = barrier.wait();
|
||||||
|
|
||||||
|
// As long as the game is still playing...
|
||||||
|
while playing.load(Ordering::SeqCst) {
|
||||||
|
let (idx, color) = player.flip_card_strategy();
|
||||||
|
ground.flip_card(idx, color);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create multiple threads for the computer's strategy
|
||||||
|
let dist = NUM_CARDS / NUM_ENEMIES;
|
||||||
|
let bot_threads: Vec<_> = (0..NUM_ENEMIES)
|
||||||
|
.map(|i| {
|
||||||
|
let ground = ground.clone();
|
||||||
|
let barrier = barrier.clone();
|
||||||
|
let playing = playing.clone();
|
||||||
|
|
||||||
|
let init = i * dist;
|
||||||
|
let mut cnt = 0;
|
||||||
|
|
||||||
|
thread::spawn(move || {
|
||||||
|
// Get, Set, Ready, Go!
|
||||||
|
let _ = barrier.wait();
|
||||||
|
|
||||||
|
// As long as the game is still playing...
|
||||||
|
while playing.load(Ordering::SeqCst) {
|
||||||
|
let idx = init + (cnt % dist);
|
||||||
|
match ground.get_card_color(idx) {
|
||||||
|
Color::White => ground.flip_card(idx, Color::Blue),
|
||||||
|
Color::Blue => thread::sleep(Duration::from_micros(1)),
|
||||||
|
};
|
||||||
|
cnt += 1;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// Get, Set, Ready, Go!
|
||||||
|
let _ = barrier.wait();
|
||||||
|
|
||||||
|
// Wait for a while and stop the game
|
||||||
|
thread::sleep(Duration::from_secs(DURATION));
|
||||||
|
playing.store(false, Ordering::SeqCst);
|
||||||
|
|
||||||
|
// Wait for all threads to finish
|
||||||
|
player_thread.join().unwrap();
|
||||||
|
for bot_thread in bot_threads {
|
||||||
|
bot_thread.join().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count the number of white and blue cards
|
||||||
|
let mut white_cnt = 0;
|
||||||
|
let mut blue_cnt = 0;
|
||||||
|
for card in ground.cards {
|
||||||
|
match card.get_color() {
|
||||||
|
Color::White => white_cnt += 1,
|
||||||
|
Color::Blue => blue_cnt += 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print the winner
|
||||||
|
println!("[White: {white_cnt}, Blue: {blue_cnt}]");
|
||||||
|
assert!(white_cnt > blue_cnt, "You lose...",);
|
||||||
|
}
|
||||||
|
}
|
||||||
37
src/assignments/assignment12/demux.rs
Normal file
37
src/assignments/assignment12/demux.rs
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
//! Demultiplexing sender
|
||||||
|
//!
|
||||||
|
//! Implement demultiplexing sender
|
||||||
|
//! Demultiplexer, `Demux` in short, is a device that has one input and many outputs.
|
||||||
|
//! It distributes the input to the outputs according to the control signal.
|
||||||
|
//! It is used when a circuit wishes to send a signal to one of many devices.
|
||||||
|
//! For more information, refer <https://www.electronics-tutorials.ws/combination/comb_3.html>
|
||||||
|
//!
|
||||||
|
//! In this assignment, closure `f` will be given as an argument to `demux` function.
|
||||||
|
//! This closure will be used to determine which destination to send the input data.
|
||||||
|
//!
|
||||||
|
//! Refer `demux_grade.rs` for test cases
|
||||||
|
|
||||||
|
use std::sync::mpsc::{channel, Receiver, SendError, Sender};
|
||||||
|
use std::thread;
|
||||||
|
|
||||||
|
/// Sender for demux.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct DemuxSender<T, F: Fn(&T) -> bool> {
|
||||||
|
tx_true: Sender<T>,
|
||||||
|
tx_false: Sender<T>,
|
||||||
|
f: F,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, F: Fn(&T) -> bool> DemuxSender<T, F> {
|
||||||
|
/// send
|
||||||
|
///
|
||||||
|
/// If `f(&value)` is true, send `value` to `tx_true`. Otherwise, send `value` to `tx_false`.
|
||||||
|
pub fn send(&self, value: T) -> Result<(), SendError<T>> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Demux.
|
||||||
|
pub fn demux<T, F: Fn(&T) -> bool>(f: F) -> (DemuxSender<T, F>, Receiver<T>, Receiver<T>) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
36
src/assignments/assignment12/demux_grade.rs
Normal file
36
src/assignments/assignment12/demux_grade.rs
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
//! Test cases for assignment12/demux.rs
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test_demux {
|
||||||
|
use super::super::demux::*;
|
||||||
|
use ntest::timeout;
|
||||||
|
|
||||||
|
use std::sync::mpsc::channel;
|
||||||
|
use std::thread;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[timeout(5000)]
|
||||||
|
fn test_demux() {
|
||||||
|
let (tx, rx1, rx2) = demux::<u32, _>(|x| x % 2 == 0);
|
||||||
|
|
||||||
|
let thread_tx = thread::spawn(move || {
|
||||||
|
for i in 0..100 {
|
||||||
|
tx.send(i).unwrap();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let thread_rx1 = thread::spawn(move || {
|
||||||
|
let sum: u32 = rx1.iter().sum();
|
||||||
|
assert_eq!(sum, (0..100).filter(|x| x % 2 == 0).sum());
|
||||||
|
});
|
||||||
|
|
||||||
|
let thread_rx2 = thread::spawn(move || {
|
||||||
|
let sum: u32 = rx2.iter().sum();
|
||||||
|
assert_eq!(sum, (0..100).filter(|x| x % 2 != 0).sum());
|
||||||
|
});
|
||||||
|
|
||||||
|
thread_tx.join().unwrap();
|
||||||
|
thread_rx1.join().unwrap();
|
||||||
|
thread_rx2.join().unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
21
src/assignments/assignment12/funnel.rs
Normal file
21
src/assignments/assignment12/funnel.rs
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
//! Funnel
|
||||||
|
//!
|
||||||
|
//! Spawn a thread that executes a funnel.
|
||||||
|
//! Funnel will receive data from multiple receivers and send it to a single sender.
|
||||||
|
//! Also, the funnel will filter out data that does not pass the filter function.
|
||||||
|
//!
|
||||||
|
//! Refer `funnel_grade.rs` for test cases
|
||||||
|
|
||||||
|
use std::sync::mpsc::{channel, Receiver, Sender};
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::thread;
|
||||||
|
use std::thread::JoinHandle;
|
||||||
|
|
||||||
|
/// Spawn a thread that concurrently receive datas from `rxs`, send it to `tx` if it makes `f` true. Returns its handle.
|
||||||
|
pub fn spawn_funnel<T, F>(rxs: Vec<Receiver<T>>, tx: Sender<T>, f: F) -> JoinHandle<()>
|
||||||
|
where
|
||||||
|
T: Send + 'static,
|
||||||
|
F: Send + Sync + Fn(&T) -> bool + 'static,
|
||||||
|
{
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
33
src/assignments/assignment12/funnel_grade.rs
Normal file
33
src/assignments/assignment12/funnel_grade.rs
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
//! Test cases for assignment12/funnel.rs
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test_funnel {
|
||||||
|
use super::super::funnel::*;
|
||||||
|
use ntest::timeout;
|
||||||
|
|
||||||
|
use std::sync::mpsc::channel;
|
||||||
|
use std::thread;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[timeout(5000)]
|
||||||
|
fn test_funnel_concurrent() {
|
||||||
|
let (txs, rxs): (Vec<_>, Vec<_>) = (0..10).map(|_| channel::<u32>()).unzip();
|
||||||
|
let (tx, rx) = channel::<u32>();
|
||||||
|
let filter = |x: &u32| x % 2 == 0;
|
||||||
|
|
||||||
|
let thread_txs_rx = thread::spawn(move || {
|
||||||
|
for i in 0..100 {
|
||||||
|
let idx = (i * 7) % 13 * 17 % 10;
|
||||||
|
txs[idx].send(i as u32).unwrap();
|
||||||
|
if i % 2 == 0 {
|
||||||
|
let x = rx.recv().unwrap();
|
||||||
|
assert_eq!(x, i as u32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let thread_funnel = spawn_funnel(rxs, tx, filter);
|
||||||
|
|
||||||
|
thread_txs_rx.join().unwrap();
|
||||||
|
thread_funnel.join().unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
15
src/assignments/assignment12/mod.rs
Normal file
15
src/assignments/assignment12/mod.rs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
//! Assignment 12: Concurrency.
|
||||||
|
//!
|
||||||
|
//! The primary goal of this assignment is to get used to concurrency.
|
||||||
|
//!
|
||||||
|
//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-12.sh` works fine.
|
||||||
|
//! See `assignment12_grade.rs` and `/scripts/grade-12.sh` for the test script.
|
||||||
|
|
||||||
|
pub mod card;
|
||||||
|
pub mod card_grade;
|
||||||
|
pub mod demux;
|
||||||
|
pub mod demux_grade;
|
||||||
|
pub mod funnel;
|
||||||
|
pub mod funnel_grade;
|
||||||
|
pub mod small_exercises;
|
||||||
|
pub mod small_exercises_grade;
|
||||||
@@ -1,23 +1,25 @@
|
|||||||
#![allow(single_use_lifetimes)]
|
#![allow(single_use_lifetimes)]
|
||||||
|
|
||||||
//! Assignment 12: Concurrency.
|
//! Small exercises
|
||||||
//!
|
//!
|
||||||
//! The primary goal of this assignment is to get used to concurrency.
|
//! Refer `small_exercises_grade.rs` for test cases
|
||||||
//!
|
|
||||||
//! You should fill out the `todo!()` placeholders in such a way that `/scripts/grade-12.sh` works fine.
|
|
||||||
//! See `assignment12_grade.rs` and `/scripts/grade-12.sh` for the test script.
|
|
||||||
|
|
||||||
use std::sync::mpsc::{Receiver, RecvError, Sender};
|
use std::sync::mpsc::{Receiver, RecvError, Sender};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
|
||||||
use etrace::*;
|
use etrace::*;
|
||||||
|
|
||||||
/// The "pong" function (read the test script to figure out what it should do).
|
/// The "pong" function
|
||||||
|
///
|
||||||
|
/// Data will be sent and received through `rx` and `tx`.
|
||||||
|
/// Read the `test_ping_pong` function in `small_exercises_grade.rs` to figure out what it should do.
|
||||||
pub fn pong(rx1: &mut Receiver<u32>, tx2: &mut Sender<u32>) -> bool {
|
pub fn pong(rx1: &mut Receiver<u32>, tx2: &mut Sender<u32>) -> bool {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Executes the given functions (f1, f2) in concurrent and returns the results.
|
/// Executes the given functions (f1, f2) in concurrent and returns the results.
|
||||||
|
///
|
||||||
|
/// Read the `test_scoped_thread` function in `small_exercises_grade.rs` to figure out what it should do.
|
||||||
pub fn use_scoped_thread<'scope, 'env, T1, T2, F1, F2>(
|
pub fn use_scoped_thread<'scope, 'env, T1, T2, F1, F2>(
|
||||||
s: &'scope thread::Scope<'scope, 'env>,
|
s: &'scope thread::Scope<'scope, 'env>,
|
||||||
f1: F1,
|
f1: F1,
|
||||||
86
src/assignments/assignment12/small_exercises_grade.rs
Normal file
86
src/assignments/assignment12/small_exercises_grade.rs
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
//! Test cases for assignment12/small_exercises_grade.rs
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test_pingpong {
|
||||||
|
use super::super::small_exercises::*;
|
||||||
|
use ntest::timeout;
|
||||||
|
|
||||||
|
use std::sync::mpsc::channel;
|
||||||
|
use std::thread;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ping_pong() {
|
||||||
|
let (tx1, mut rx1) = channel();
|
||||||
|
let (mut tx2, rx2) = channel();
|
||||||
|
|
||||||
|
let thread_ping = thread::spawn(move || {
|
||||||
|
for i in 0..100 {
|
||||||
|
tx1.send(i).unwrap();
|
||||||
|
let x = rx2.recv().unwrap();
|
||||||
|
assert_eq!(x, i + 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let thread_pong = thread::spawn(move || while pong(&mut rx1, &mut tx2) {});
|
||||||
|
|
||||||
|
thread_ping.join().unwrap();
|
||||||
|
thread_pong.join().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_scoped_thread() {
|
||||||
|
for i in 0..100 {
|
||||||
|
let v = (0..i).collect::<Vec<u32>>();
|
||||||
|
|
||||||
|
thread::scope(|s| {
|
||||||
|
let (r1, r2) = use_scoped_thread(
|
||||||
|
s,
|
||||||
|
|| v.iter().sum::<u32>(),
|
||||||
|
|| v.windows(2).map(|x| x[0] * x[1]).sum::<u32>(),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(r1, v.iter().sum());
|
||||||
|
assert_eq!(r2, v.windows(2).map(|x| x[0] * x[1]).sum());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[timeout(5000)]
|
||||||
|
fn test_scoped_thread_concurrent() {
|
||||||
|
use std::sync::Mutex;
|
||||||
|
|
||||||
|
let m = Mutex::new(0);
|
||||||
|
let (r1, r2) = thread::scope(|s| {
|
||||||
|
use_scoped_thread(
|
||||||
|
s,
|
||||||
|
|| {
|
||||||
|
for i in 0..100 {
|
||||||
|
loop {
|
||||||
|
let mut a = m.lock().unwrap();
|
||||||
|
if *a == 2 * i {
|
||||||
|
*a += 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
thread::current().id()
|
||||||
|
},
|
||||||
|
|| {
|
||||||
|
for i in 0..100 {
|
||||||
|
loop {
|
||||||
|
let mut a = m.lock().unwrap();
|
||||||
|
if *a == 2 * i + 1 {
|
||||||
|
*a += 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
thread::current().id()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
assert!(r1 != r2);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,8 +25,6 @@ mod assignment09_grade;
|
|||||||
pub mod assignment10;
|
pub mod assignment10;
|
||||||
mod assignment10_grade;
|
mod assignment10_grade;
|
||||||
pub mod assignment11;
|
pub mod assignment11;
|
||||||
mod assignment11_grade;
|
|
||||||
pub mod assignment12;
|
pub mod assignment12;
|
||||||
mod assignment12_grade;
|
|
||||||
pub mod assignment13;
|
pub mod assignment13;
|
||||||
mod assignment13_grade;
|
mod assignment13_grade;
|
||||||
|
|||||||
Reference in New Issue
Block a user