first version draft
This commit is contained in:
Generated
+472
@@ -2,6 +2,478 @@
|
|||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 4
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "arrayvec"
|
||||||
|
version = "0.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bumpalo"
|
||||||
|
version = "3.20.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chacha20"
|
||||||
|
version = "0.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d524456ba66e72eb8b115ff89e01e497f8e6d11d78b70b1aa13c0fbd97540a81"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"cpufeatures",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colored"
|
||||||
|
version = "3.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34"
|
||||||
|
dependencies = [
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "console"
|
||||||
|
version = "0.16.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4fe5f465a4f6fee88fad41b85d990f84c835335e85b5d9e6e63e0d06d28cba7c"
|
||||||
|
dependencies = [
|
||||||
|
"encode_unicode",
|
||||||
|
"libc",
|
||||||
|
"unicode-width 0.2.2",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "convert_case"
|
||||||
|
version = "0.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-segmentation",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cpufeatures"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-deque"
|
||||||
|
version = "0.8.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5181e0de7b61eb03a81e347d6dd8797bae9da5146707b51077e2d71a54ec0ceb"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-epoch",
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-epoch"
|
||||||
|
version = "0.9.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2d6914041f254d6e9176c01941b21115dcfb7089e55135a35411081bd106ef3f"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-utils"
|
||||||
|
version = "0.8.22"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "derive_more"
|
||||||
|
version = "2.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134"
|
||||||
|
dependencies = [
|
||||||
|
"derive_more-impl",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "derive_more-impl"
|
||||||
|
version = "2.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb"
|
||||||
|
dependencies = [
|
||||||
|
"convert_case",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"rustc_version",
|
||||||
|
"syn",
|
||||||
|
"unicode-xid",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.17.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9e5e8f6c15a24b9a3ee5efec809ccd006d3b30e8b3bb63c39af737c7f87daa1d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "encode_unicode"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-core"
|
||||||
|
version = "0.3.34"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-task"
|
||||||
|
version = "0.3.34"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-util"
|
||||||
|
version = "0.3.34"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc"
|
||||||
|
dependencies = [
|
||||||
|
"futures-core",
|
||||||
|
"futures-task",
|
||||||
|
"pin-project-lite",
|
||||||
|
"slab",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "getrandom"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"r-efi",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "indicatif"
|
||||||
|
version = "0.18.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9433806cd6b4ec1aba79c021c7e4c58fb4c3b9977c085062e611ac929998fb0c"
|
||||||
|
dependencies = [
|
||||||
|
"console",
|
||||||
|
"portable-atomic",
|
||||||
|
"rayon",
|
||||||
|
"unicode-width 0.2.2",
|
||||||
|
"unit-prefix",
|
||||||
|
"web-time",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "js-sys"
|
||||||
|
version = "0.3.104"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0e0c1080212aad755ea003d18543e8768dd432c48819efd73a7bf1e39b7a5a3a"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"futures-util",
|
||||||
|
"wasm-bindgen",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.189"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "once_cell"
|
||||||
|
version = "1.21.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pin-project-lite"
|
||||||
|
version = "0.2.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "portable-atomic"
|
||||||
|
version = "1.15.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.107"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.47"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "r-efi"
|
||||||
|
version = "6.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand"
|
||||||
|
version = "0.10.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80"
|
||||||
|
dependencies = [
|
||||||
|
"chacha20",
|
||||||
|
"getrandom",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rayon"
|
||||||
|
version = "1.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
"rayon-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rayon-core"
|
||||||
|
version = "1.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-deque",
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc_version"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
|
||||||
|
dependencies = [
|
||||||
|
"semver",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustversion"
|
||||||
|
version = "1.0.23"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "semver"
|
||||||
|
version = "1.0.28"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "slab"
|
||||||
|
version = "0.4.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strip-ansi-escapes"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "011cbb39cf7c1f62871aea3cc46e5817b0937b49e9447370c93cacbe93a766d8"
|
||||||
|
dependencies = [
|
||||||
|
"vte",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "2.0.119"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tabular"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d9a2882c514780a1973df90de9d68adcd8871bacc9a6331c3f28e6d2ff91a3d1"
|
||||||
|
dependencies = [
|
||||||
|
"strip-ansi-escapes",
|
||||||
|
"unicode-width 0.1.14",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.24"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-segmentation"
|
||||||
|
version = "1.13.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-width"
|
||||||
|
version = "0.1.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-width"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-xid"
|
||||||
|
version = "0.2.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unit-prefix"
|
||||||
|
version = "0.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "81e544489bf3d8ef66c953931f56617f423cd4b5494be343d9b9d3dda037b9a3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "utf8parse"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "vte"
|
||||||
|
version = "0.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6cbce692ab4ca2f1f3047fcf732430249c0e971bfdd2b234cf2c47ad93af5983"
|
||||||
|
dependencies = [
|
||||||
|
"arrayvec",
|
||||||
|
"utf8parse",
|
||||||
|
"vte_generate_state_changes",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "vte_generate_state_changes"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2e369bee1b05d510a7b4ed645f5faa90619e05437111783ea5848f28d97d3c2e"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen"
|
||||||
|
version = "0.2.127"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1b70935747edd64d89de3efa29d73789b806c15798f8e7dca4d8ac356b50ce70"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"once_cell",
|
||||||
|
"rustversion",
|
||||||
|
"wasm-bindgen-macro",
|
||||||
|
"wasm-bindgen-shared",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen-macro"
|
||||||
|
version = "0.2.127"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "77775f8f3f7217702089053b94958f8f54061a3f663417df76e19cbdcca29bc1"
|
||||||
|
dependencies = [
|
||||||
|
"quote",
|
||||||
|
"wasm-bindgen-macro-support",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen-macro-support"
|
||||||
|
version = "0.2.127"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e11d33f857dc2fb11b8bc75aee111aa9cbeb12cd9f25efd3d4c2a3dd4e235284"
|
||||||
|
dependencies = [
|
||||||
|
"bumpalo",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"wasm-bindgen-shared",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen-shared"
|
||||||
|
version = "0.2.127"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7ef64dbcc55df09c7e5a46182d181c2cfa3e925f3da937ea764728b4bbb9dcbf"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "web-time"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb"
|
||||||
|
dependencies = [
|
||||||
|
"js-sys",
|
||||||
|
"wasm-bindgen",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-link"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.61.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
|
||||||
|
dependencies = [
|
||||||
|
"windows-link",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wordle-solver"
|
name = "wordle-solver"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"colored",
|
||||||
|
"derive_more",
|
||||||
|
"indicatif",
|
||||||
|
"rand",
|
||||||
|
"rayon",
|
||||||
|
"tabular",
|
||||||
|
]
|
||||||
|
|||||||
+14
-2
@@ -8,8 +8,20 @@ edition = "2021"
|
|||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "wordle_solver"
|
name = "wordle_solver"
|
||||||
path = "src/lib.rs"
|
path = "src/lib/lib.rs"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "wordle_solver"
|
name = "wordle-solver"
|
||||||
path = "src/app/wordle_solver.rs"
|
path = "src/app/wordle_solver.rs"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "wordle-simulation"
|
||||||
|
path = "src/app/wordle_simulation.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
colored = "3.1.1"
|
||||||
|
derive_more = { version = "2.1.1", features = [ "debug", "display" ] }
|
||||||
|
indicatif = { version = "0.18.6", features = ["rayon"] }
|
||||||
|
rand = "0.10.2"
|
||||||
|
rayon = "1.12.0"
|
||||||
|
tabular = { version = "0.2.0", features = ["ansi-cell"] }
|
||||||
|
|||||||
+2315
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,33 @@
|
|||||||
|
use std::{env::args, path::Path};
|
||||||
|
|
||||||
|
use wordle_solver::{game::Game, solver::Solver, word_list::WordList};
|
||||||
|
|
||||||
|
pub fn main() {
|
||||||
|
let valid_words = WordList::from_file(Path::new("valid-words.txt")).unwrap();
|
||||||
|
let target_words = WordList::from_file(Path::new("answers.txt")).unwrap();
|
||||||
|
let mut game = Game::new(target_words.random_word());
|
||||||
|
|
||||||
|
let mut solver = Solver::new(valid_words, target_words);
|
||||||
|
|
||||||
|
if let Some(first_guess) = args().skip(1).next() {
|
||||||
|
if let Some(pat) = game.guess(&first_guess) {
|
||||||
|
solver.apply_guess(pat);
|
||||||
|
println!("{}", solver.tabular_format());
|
||||||
|
} else {
|
||||||
|
println!("Found solution: {}", first_guess);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let best_word = &solver.evaluate_all_words().first().unwrap().clone().word;
|
||||||
|
println!("{}", solver.best_word_format());
|
||||||
|
|
||||||
|
if let Some(pat) = game.guess(best_word) {
|
||||||
|
solver.apply_guess(pat);
|
||||||
|
println!("{}", solver.tabular_format());
|
||||||
|
} else {
|
||||||
|
println!("Found solution: {}", best_word);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,21 @@
|
|||||||
use wordle_solver::foo;
|
use std::path::Path;
|
||||||
|
|
||||||
|
use wordle_solver::{pattern::Pattern, solver::Solver, word_list::WordList};
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
foo()
|
let wl = WordList::from_file(Path::new("valid-words.csv")).unwrap();
|
||||||
|
|
||||||
|
let mut solver = Solver::from_single_word_list(wl);
|
||||||
|
|
||||||
|
solver.apply_guess(Pattern::from_guess("CRANE", "CASTS").unwrap());
|
||||||
|
println!("{}", solver.tabular_format());
|
||||||
|
println!("{}", solver.best_word_format());
|
||||||
|
|
||||||
|
solver.apply_guess(Pattern::from_guess("CRANE", "WORKS").unwrap());
|
||||||
|
println!("{}", solver.tabular_format());
|
||||||
|
println!("{}", solver.best_word_format());
|
||||||
|
|
||||||
|
solver.apply_guess(Pattern::from_guess("CRANE", "PAPER").unwrap());
|
||||||
|
println!("{}", solver.tabular_format());
|
||||||
|
println!("{}", solver.best_word_format());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
pub fn foo() {
|
|
||||||
println!("Hello from wordle-solver");
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
use crate::pattern::Pattern;
|
||||||
|
|
||||||
|
pub struct Game {
|
||||||
|
score: u64,
|
||||||
|
word: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Game {
|
||||||
|
pub fn new(word: &str) -> Game {
|
||||||
|
Game {
|
||||||
|
score: 0,
|
||||||
|
word: word.to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn guess(&mut self, word: &str) -> Option<Pattern> {
|
||||||
|
self.score += 1;
|
||||||
|
|
||||||
|
if word == self.word {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(Pattern::from_guess(&self.word, word).unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
pub mod game;
|
||||||
|
pub mod pattern;
|
||||||
|
pub mod solver;
|
||||||
|
pub mod word_list;
|
||||||
@@ -0,0 +1,270 @@
|
|||||||
|
use colored::Colorize;
|
||||||
|
use derive_more::Display;
|
||||||
|
|
||||||
|
#[derive(Display, Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
|
||||||
|
pub enum CharStatus {
|
||||||
|
GREY,
|
||||||
|
YELLOW,
|
||||||
|
GREEN,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct Pattern {
|
||||||
|
chars: Vec<char>,
|
||||||
|
stats: Vec<CharStatus>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Pattern {
|
||||||
|
pub fn ansi_format(&self) -> String {
|
||||||
|
self.chars
|
||||||
|
.iter()
|
||||||
|
.zip(self.stats.iter())
|
||||||
|
.map(|(c, s)| match s {
|
||||||
|
CharStatus::GREEN => c.to_string().green().to_string(),
|
||||||
|
CharStatus::YELLOW => c.to_string().yellow().to_string(),
|
||||||
|
CharStatus::GREY => c.to_string().truecolor(100, 100, 100).to_string(),
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_new(word: &str, stats: Vec<CharStatus>) -> Result<Pattern, String> {
|
||||||
|
if word.len() != stats.len() {
|
||||||
|
Err(format!(
|
||||||
|
"Word length ({}) does not match stats length ({})",
|
||||||
|
word.len(),
|
||||||
|
stats.len()
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
Ok(Pattern {
|
||||||
|
chars: word.chars().collect(),
|
||||||
|
stats,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_guess(word: &str, guess: &str) -> Result<Pattern, String> {
|
||||||
|
if word.len() != guess.len() {
|
||||||
|
return Err(format!(
|
||||||
|
"Word length ({}) does not match guess length ({})",
|
||||||
|
word.len(),
|
||||||
|
guess.len()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let guess: Vec<char> = guess.chars().collect();
|
||||||
|
let chars: Vec<char> = word.chars().collect();
|
||||||
|
let mut stats: Vec<CharStatus> = vec![CharStatus::GREY; chars.len()];
|
||||||
|
let mut rest = chars.clone();
|
||||||
|
|
||||||
|
// Greens
|
||||||
|
for i in 0..chars.len() {
|
||||||
|
if chars[i] == guess[i] {
|
||||||
|
stats[i] = CharStatus::GREEN;
|
||||||
|
rest[i] = ' ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Yellows
|
||||||
|
for i in 0..chars.len() {
|
||||||
|
if let Some((j, _)) = rest.iter().enumerate().find(|(_, x)| **x == guess[i]) {
|
||||||
|
stats[i] = CharStatus::YELLOW;
|
||||||
|
rest[j] = ' ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Pattern {
|
||||||
|
chars: guess,
|
||||||
|
stats,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn matches(&self, word: &Vec<char>) -> bool {
|
||||||
|
let mut rest = word.clone();
|
||||||
|
|
||||||
|
if word.len() != self.chars.len() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Green + trivial yellow check
|
||||||
|
for (i, s) in self.stats.iter().enumerate() {
|
||||||
|
match *s {
|
||||||
|
CharStatus::GREEN => {
|
||||||
|
if self.chars[i] != rest[i] {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
rest[i] = ' ';
|
||||||
|
}
|
||||||
|
CharStatus::YELLOW => {
|
||||||
|
if self.chars[i] == rest[i] {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CharStatus::GREY => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Yellow check
|
||||||
|
for (i, s) in self.stats.iter().enumerate() {
|
||||||
|
if *s != CharStatus::YELLOW {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if let Some((j, _)) = rest.iter().enumerate().find(|(_, x)| **x == self.chars[i]) {
|
||||||
|
rest[j] = ' ';
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Grey check
|
||||||
|
for (i, s) in self.stats.iter().enumerate() {
|
||||||
|
if *s != CharStatus::GREY {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if let Some(_) = rest.iter().find(|x| **x == self.chars[i]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pattern_from_guess() {
|
||||||
|
assert_eq!(
|
||||||
|
Pattern::from_guess("abcde", "abcde"),
|
||||||
|
Pattern::try_new(
|
||||||
|
"abcde",
|
||||||
|
vec![
|
||||||
|
CharStatus::GREEN,
|
||||||
|
CharStatus::GREEN,
|
||||||
|
CharStatus::GREEN,
|
||||||
|
CharStatus::GREEN,
|
||||||
|
CharStatus::GREEN,
|
||||||
|
]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Pattern::from_guess("abcde", "eabcd"),
|
||||||
|
Pattern::try_new(
|
||||||
|
"abcde",
|
||||||
|
vec![
|
||||||
|
CharStatus::YELLOW,
|
||||||
|
CharStatus::YELLOW,
|
||||||
|
CharStatus::YELLOW,
|
||||||
|
CharStatus::YELLOW,
|
||||||
|
CharStatus::YELLOW,
|
||||||
|
]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Pattern::from_guess("abcde", "fghij"),
|
||||||
|
Pattern::try_new(
|
||||||
|
"abcde",
|
||||||
|
vec![
|
||||||
|
CharStatus::GREY,
|
||||||
|
CharStatus::GREY,
|
||||||
|
CharStatus::GREY,
|
||||||
|
CharStatus::GREY,
|
||||||
|
CharStatus::GREY,
|
||||||
|
]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Pattern::from_guess("aabbc", "bbaab"),
|
||||||
|
Pattern::try_new(
|
||||||
|
"aabbc",
|
||||||
|
vec![
|
||||||
|
CharStatus::YELLOW,
|
||||||
|
CharStatus::YELLOW,
|
||||||
|
CharStatus::YELLOW,
|
||||||
|
CharStatus::YELLOW,
|
||||||
|
CharStatus::GREY,
|
||||||
|
]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pattern_match_1() {
|
||||||
|
let p1 = Pattern::try_new(
|
||||||
|
"abcde",
|
||||||
|
vec![
|
||||||
|
CharStatus::GREY,
|
||||||
|
CharStatus::GREY,
|
||||||
|
CharStatus::GREY,
|
||||||
|
CharStatus::GREY,
|
||||||
|
CharStatus::GREY,
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert!(p1.matches(&"fghij".chars().collect()));
|
||||||
|
assert!(!p1.matches(&"f".chars().collect()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pattern_match_2() {
|
||||||
|
let p1 = Pattern::try_new(
|
||||||
|
"abcde",
|
||||||
|
vec![
|
||||||
|
CharStatus::GREY,
|
||||||
|
CharStatus::GREY,
|
||||||
|
CharStatus::GREEN,
|
||||||
|
CharStatus::GREY,
|
||||||
|
CharStatus::GREY,
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert!(!p1.matches(&"fghij".chars().collect()));
|
||||||
|
assert!(!p1.matches(&"abcde".chars().collect()));
|
||||||
|
assert!(p1.matches(&"ffcff".chars().collect()));
|
||||||
|
assert!(p1.matches(&"ccccc".chars().collect()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pattern_match_3() {
|
||||||
|
let p1 = Pattern::try_new(
|
||||||
|
"abcde",
|
||||||
|
vec![
|
||||||
|
CharStatus::GREEN,
|
||||||
|
CharStatus::GREEN,
|
||||||
|
CharStatus::GREEN,
|
||||||
|
CharStatus::GREEN,
|
||||||
|
CharStatus::GREEN,
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert!(!p1.matches(&"fghij".chars().collect()));
|
||||||
|
assert!(p1.matches(&"abcde".chars().collect()));
|
||||||
|
assert!(!p1.matches(&"abcdf".chars().collect()));
|
||||||
|
assert!(!p1.matches(&"abced".chars().collect()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pattern_match_4() {
|
||||||
|
let p1 = Pattern::try_new(
|
||||||
|
"aabbcc",
|
||||||
|
vec![
|
||||||
|
CharStatus::YELLOW,
|
||||||
|
CharStatus::YELLOW,
|
||||||
|
CharStatus::YELLOW,
|
||||||
|
CharStatus::GREY,
|
||||||
|
CharStatus::YELLOW,
|
||||||
|
CharStatus::GREEN,
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert!(p1.matches(&"bcaafc".chars().collect()));
|
||||||
|
assert!(!p1.matches(&"bfaafc".chars().collect()));
|
||||||
|
assert!(!p1.matches(&"bbaafc".chars().collect()));
|
||||||
|
assert!(!p1.matches(&"aabfcc".chars().collect()));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,154 @@
|
|||||||
|
use crate::pattern::Pattern;
|
||||||
|
use indicatif::ParallelProgressIterator;
|
||||||
|
use rayon::iter::{ParallelBridge, ParallelIterator};
|
||||||
|
|
||||||
|
use crate::word_list::WordList;
|
||||||
|
|
||||||
|
use derive_more::Display;
|
||||||
|
use tabular::{Row, Table};
|
||||||
|
|
||||||
|
struct Guess {
|
||||||
|
pattern: Pattern,
|
||||||
|
information_gained: f64,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Solver {
|
||||||
|
valid_words: WordList,
|
||||||
|
possible_solutions: WordList,
|
||||||
|
guesses: Vec<Guess>,
|
||||||
|
best_words: Vec<WordStats>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Display, Clone)]
|
||||||
|
#[display(
|
||||||
|
"WordStats({}, p={:.02}%, E[I]={:.02}, E[s]={:.02})",
|
||||||
|
word,
|
||||||
|
solution_probability*100.0,
|
||||||
|
expected_information_gained,
|
||||||
|
expected_score_after_guess
|
||||||
|
)]
|
||||||
|
pub struct WordStats {
|
||||||
|
pub word: String,
|
||||||
|
pub solution_probability: f64,
|
||||||
|
pub expected_information_gained: f64,
|
||||||
|
pub expected_score_after_guess: f64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Solver {
|
||||||
|
pub fn from_single_word_list(word_list: WordList) -> Solver {
|
||||||
|
Solver {
|
||||||
|
valid_words: word_list.clone(),
|
||||||
|
possible_solutions: word_list,
|
||||||
|
guesses: vec![],
|
||||||
|
best_words: vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(valid_words: WordList, possible_solutions: WordList) -> Solver {
|
||||||
|
Solver {
|
||||||
|
valid_words,
|
||||||
|
possible_solutions,
|
||||||
|
guesses: vec![],
|
||||||
|
best_words: vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn apply_guess(&mut self, guess: Pattern) {
|
||||||
|
let new_possible_solutions = self.possible_solutions.apply_guess(&guess);
|
||||||
|
let information_gained = self.possible_solutions.equal_likelieness_entropy()
|
||||||
|
- new_possible_solutions.equal_likelieness_entropy();
|
||||||
|
|
||||||
|
self.possible_solutions = new_possible_solutions;
|
||||||
|
|
||||||
|
self.guesses.push(Guess {
|
||||||
|
pattern: guess,
|
||||||
|
information_gained,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn evaluate_word(&self, word: &str) -> WordStats {
|
||||||
|
let solution_probability = self.possible_solutions.word_probability(word);
|
||||||
|
|
||||||
|
let expected_information_gained = self.possible_solutions.entropy_if_guessed(word);
|
||||||
|
|
||||||
|
let score = (self.guesses.len() + 1) as f64;
|
||||||
|
|
||||||
|
let expected_score_after_guess = score * solution_probability
|
||||||
|
+ (1.0 - solution_probability)
|
||||||
|
* (score
|
||||||
|
+ ((self.valid_words.equal_likelieness_entropy()
|
||||||
|
- expected_information_gained)
|
||||||
|
.log2()
|
||||||
|
+ 1.0));
|
||||||
|
|
||||||
|
WordStats {
|
||||||
|
word: word.to_string(),
|
||||||
|
solution_probability,
|
||||||
|
expected_information_gained,
|
||||||
|
expected_score_after_guess,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn evaluate_all_words(&mut self) -> Vec<WordStats> {
|
||||||
|
self.best_words = self
|
||||||
|
.valid_words
|
||||||
|
.words()
|
||||||
|
.par_bridge()
|
||||||
|
.progress_count(self.valid_words.len() as u64)
|
||||||
|
.map(|w| self.evaluate_word(w))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
self.best_words.sort_by(|a, b| {
|
||||||
|
a.expected_score_after_guess
|
||||||
|
.total_cmp(&b.expected_score_after_guess)
|
||||||
|
});
|
||||||
|
|
||||||
|
self.best_words.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn best_word_format(&self) -> String {
|
||||||
|
let mut table = Table::new("#{:<} {:>} | {:<} {:<} {:<}");
|
||||||
|
|
||||||
|
table.add_row(
|
||||||
|
Row::new()
|
||||||
|
.with_cell("Best")
|
||||||
|
.with_cell("Word")
|
||||||
|
.with_cell("p[solution]")
|
||||||
|
.with_cell("E[I]")
|
||||||
|
.with_cell("E[score]"),
|
||||||
|
);
|
||||||
|
for (i, ws) in self.best_words.iter().take(10).enumerate() {
|
||||||
|
table.add_row(
|
||||||
|
Row::new()
|
||||||
|
.with_cell(i + 1)
|
||||||
|
.with_cell(&ws.word)
|
||||||
|
.with_cell(ws.solution_probability)
|
||||||
|
.with_cell(ws.expected_information_gained)
|
||||||
|
.with_cell(ws.expected_score_after_guess),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
table.to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tabular_format(&self) -> String {
|
||||||
|
let mut table = Table::new("{:<} | {:<}");
|
||||||
|
|
||||||
|
table.add_row(Row::new().with_cell("Guess").with_cell("Info-Gained"));
|
||||||
|
|
||||||
|
for g in &self.guesses {
|
||||||
|
table.add_row(
|
||||||
|
Row::new()
|
||||||
|
.with_ansi_cell(g.pattern.ansi_format())
|
||||||
|
.with_cell(format!("{:.04}", g.information_gained)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
format!(
|
||||||
|
"Solution Space: {}, Uncertainty: {:.02} bits\n{}",
|
||||||
|
self.possible_solutions.len(),
|
||||||
|
self.possible_solutions.equal_likelieness_entropy(),
|
||||||
|
table
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
use rand::{rng, seq::IteratorRandom};
|
||||||
|
use std::{
|
||||||
|
collections::{hash_set, HashSet},
|
||||||
|
fs::{self},
|
||||||
|
io::{self, BufRead},
|
||||||
|
path::Path,
|
||||||
|
};
|
||||||
|
|
||||||
|
use derive_more::Display;
|
||||||
|
|
||||||
|
use crate::pattern::Pattern;
|
||||||
|
|
||||||
|
#[derive(Display, Clone)]
|
||||||
|
#[display("{:?}", words)]
|
||||||
|
pub struct WordList {
|
||||||
|
words: HashSet<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WordList {
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.words.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_file(file: &Path) -> Result<WordList, String> {
|
||||||
|
let file = fs::File::open(file).map_err(|e| e.to_string())?;
|
||||||
|
let mut len = None;
|
||||||
|
let words: Result<HashSet<String>, String> = io::BufReader::new(file)
|
||||||
|
.lines()
|
||||||
|
.map_while(Result::ok)
|
||||||
|
.map(|s| s.trim_ascii().to_ascii_uppercase())
|
||||||
|
.filter(|s| !s.is_empty())
|
||||||
|
.map(|s| {
|
||||||
|
if !s.chars().all(|c| c.is_ascii_alphabetic()) {
|
||||||
|
return Err(format!("Word {} is not ascii alphabetic", s));
|
||||||
|
}
|
||||||
|
if let Some(len) = len {
|
||||||
|
if len == s.len() {
|
||||||
|
return Ok(s);
|
||||||
|
} else {
|
||||||
|
return Err(format!(
|
||||||
|
"Word {} does not match initial length of {}",
|
||||||
|
s, len
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
len = Some(s.len());
|
||||||
|
return Ok(s);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
Ok(WordList { words: words? })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn apply_guess(&self, pat: &Pattern) -> WordList {
|
||||||
|
WordList {
|
||||||
|
words: self
|
||||||
|
.words
|
||||||
|
.iter()
|
||||||
|
.filter(|w| pat.matches(&w.chars().collect()))
|
||||||
|
.map(Clone::clone)
|
||||||
|
.collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn count_matches(&self, pat: &Pattern) -> usize {
|
||||||
|
self.words
|
||||||
|
.iter()
|
||||||
|
.filter(|w| pat.matches(&w.chars().collect()))
|
||||||
|
.count()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn entropy_if_guessed(&self, word: &str) -> f64 {
|
||||||
|
let mut e = 0.0;
|
||||||
|
|
||||||
|
let mut observed_patterns = HashSet::new();
|
||||||
|
|
||||||
|
for w in self.words.iter() {
|
||||||
|
let pat = Pattern::from_guess(w, word).unwrap();
|
||||||
|
if observed_patterns.contains(&pat) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let m = self.count_matches(&pat);
|
||||||
|
observed_patterns.insert(pat);
|
||||||
|
if m != 0 {
|
||||||
|
let p = m as f64 / self.words.len() as f64;
|
||||||
|
e += p * (1.0 / p).log2();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
e
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn word_probability(&self, word: &str) -> f64 {
|
||||||
|
if self.words.contains(word) {
|
||||||
|
1.0 / self.words.len() as f64
|
||||||
|
} else {
|
||||||
|
0.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn contains(&self, word: &str) -> bool {
|
||||||
|
self.words.contains(word)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn words<'a>(&'a self) -> hash_set::Iter<'a, String> {
|
||||||
|
self.words.iter()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn equal_likelieness_entropy(&self) -> f64 {
|
||||||
|
let p = 1.0 / self.words.len() as f64;
|
||||||
|
-p.log2()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn random_word<'a>(&'a self) -> &'a str {
|
||||||
|
self.words.iter().choose(&mut rng()).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
+12972
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user