initial commit
This commit is contained in:
commit
c44fc69893
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
/target
|
||||||
427
Cargo.lock
generated
Normal file
427
Cargo.lock
generated
Normal file
|
|
@ -0,0 +1,427 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "approx"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "2.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bytemuck"
|
||||||
|
version = "1.21.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byteorder"
|
||||||
|
version = "1.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "getrandom"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"wasi",
|
||||||
|
"windows-targets",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.169"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "matrixmultiply"
|
||||||
|
version = "0.3.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9380b911e3e96d10c1f415da0876389aaf1b56759054eeb0de7df940c456ba1a"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"rawpointer",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nalgebra"
|
||||||
|
version = "0.33.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "26aecdf64b707efd1310e3544d709c5c0ac61c13756046aaaba41be5c4f66a3b"
|
||||||
|
dependencies = [
|
||||||
|
"approx",
|
||||||
|
"matrixmultiply",
|
||||||
|
"nalgebra-macros",
|
||||||
|
"num-complex",
|
||||||
|
"num-rational",
|
||||||
|
"num-traits",
|
||||||
|
"simba",
|
||||||
|
"typenum",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nalgebra-macros"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "254a5372af8fc138e36684761d3c0cdb758a4410e938babcff1c860ce14ddbfc"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23"
|
||||||
|
dependencies = [
|
||||||
|
"num-bigint",
|
||||||
|
"num-complex",
|
||||||
|
"num-integer",
|
||||||
|
"num-iter",
|
||||||
|
"num-rational",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-bigint"
|
||||||
|
version = "0.4.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
|
||||||
|
dependencies = [
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-complex"
|
||||||
|
version = "0.4.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-integer"
|
||||||
|
version = "0.1.46"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-iter"
|
||||||
|
version = "0.1.45"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-rational"
|
||||||
|
version = "0.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824"
|
||||||
|
dependencies = [
|
||||||
|
"num-bigint",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-traits"
|
||||||
|
version = "0.2.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "paste"
|
||||||
|
version = "1.0.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "perfectset"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"nalgebra",
|
||||||
|
"num",
|
||||||
|
"rand",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ppv-lite86"
|
||||||
|
version = "0.2.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
|
||||||
|
dependencies = [
|
||||||
|
"zerocopy 0.7.35",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.93"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.38"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94"
|
||||||
|
dependencies = [
|
||||||
|
"rand_chacha",
|
||||||
|
"rand_core",
|
||||||
|
"zerocopy 0.8.17",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_chacha"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
|
||||||
|
dependencies = [
|
||||||
|
"ppv-lite86",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b08f3c9802962f7e1b25113931d94f43ed9725bebc59db9d0c3e9a23b67e15ff"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom",
|
||||||
|
"zerocopy 0.8.17",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rawpointer"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "safe_arch"
|
||||||
|
version = "0.7.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "96b02de82ddbe1b636e6170c21be622223aea188ef2e139be0a5b219ec215323"
|
||||||
|
dependencies = [
|
||||||
|
"bytemuck",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "simba"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b3a386a501cd104797982c15ae17aafe8b9261315b5d07e3ec803f2ea26be0fa"
|
||||||
|
dependencies = [
|
||||||
|
"approx",
|
||||||
|
"num-complex",
|
||||||
|
"num-traits",
|
||||||
|
"paste",
|
||||||
|
"wide",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "2.0.98"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typenum"
|
||||||
|
version = "1.17.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.16"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasi"
|
||||||
|
version = "0.13.3+wasi-0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2"
|
||||||
|
dependencies = [
|
||||||
|
"wit-bindgen-rt",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wide"
|
||||||
|
version = "0.7.32"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "41b5576b9a81633f3e8df296ce0063042a73507636cbe956c61133dd7034ab22"
|
||||||
|
dependencies = [
|
||||||
|
"bytemuck",
|
||||||
|
"safe_arch",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-targets"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_gnullvm",
|
||||||
|
"windows_aarch64_msvc",
|
||||||
|
"windows_i686_gnu",
|
||||||
|
"windows_i686_gnullvm",
|
||||||
|
"windows_i686_msvc",
|
||||||
|
"windows_x86_64_gnu",
|
||||||
|
"windows_x86_64_gnullvm",
|
||||||
|
"windows_x86_64_msvc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_gnullvm"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnullvm"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnu"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnullvm"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_msvc"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wit-bindgen-rt"
|
||||||
|
version = "0.33.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zerocopy"
|
||||||
|
version = "0.7.35"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder",
|
||||||
|
"zerocopy-derive 0.7.35",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zerocopy"
|
||||||
|
version = "0.8.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "aa91407dacce3a68c56de03abe2760159582b846c6a4acd2f456618087f12713"
|
||||||
|
dependencies = [
|
||||||
|
"zerocopy-derive 0.8.17",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zerocopy-derive"
|
||||||
|
version = "0.7.35"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zerocopy-derive"
|
||||||
|
version = "0.8.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "06718a168365cad3d5ff0bb133aad346959a2074bd4a85c121255a11304a8626"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
9
Cargo.toml
Normal file
9
Cargo.toml
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
[package]
|
||||||
|
name = "perfectset"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
nalgebra = "0.33.2"
|
||||||
|
num = "0.4.3"
|
||||||
|
rand = "0.9.0"
|
||||||
208
src/card.rs
Normal file
208
src/card.rs
Normal file
|
|
@ -0,0 +1,208 @@
|
||||||
|
use crate::f3::F3;
|
||||||
|
use nalgebra::{Matrix4, Vector4};
|
||||||
|
use num::traits::Zero;
|
||||||
|
use rand::distr::{Distribution, StandardUniform};
|
||||||
|
use rand::Rng;
|
||||||
|
use std::fmt::{Display, Formatter};
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct Card {
|
||||||
|
v: Vector4<F3>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Card {
|
||||||
|
pub fn new(number: u8, shading: u8, color: u8, shape: u8) -> Self {
|
||||||
|
Card {
|
||||||
|
v: Vector4::<F3>::new(
|
||||||
|
number.try_into().unwrap(),
|
||||||
|
shading.try_into().unwrap(),
|
||||||
|
color.try_into().unwrap(),
|
||||||
|
shape.try_into().unwrap(),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Card {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let number = match self.v.x.into() {
|
||||||
|
0 => "one",
|
||||||
|
1 => "two",
|
||||||
|
2 => "three",
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
let shading = match self.v.y.into() {
|
||||||
|
0 => "solid",
|
||||||
|
1 => "striped",
|
||||||
|
2 => "open",
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
let color = match self.v.z.into() {
|
||||||
|
0 => "red",
|
||||||
|
1 => "green",
|
||||||
|
2 => "purple",
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
let shape = match self.v.w.into() {
|
||||||
|
0 => "ovals",
|
||||||
|
1 => "squiggles",
|
||||||
|
2 => "diamonds",
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
write!(f, "{}-{}-{}-{}", number, shading, color, shape)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Distribution<Card> for StandardUniform {
|
||||||
|
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Card {
|
||||||
|
Card {
|
||||||
|
v: Vector4::<F3>::from_fn(|_, _| rng.random()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CardSet {
|
||||||
|
cards: Vec<Card>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CardSet {
|
||||||
|
pub fn new(cards: &[Card]) -> Self {
|
||||||
|
CardSet {
|
||||||
|
cards: Vec::from(cards),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn grid(&self) -> [[[[bool; 3]; 3]; 3]; 3] {
|
||||||
|
let mut grid = [[[[false; 3]; 3]; 3]; 3];
|
||||||
|
for card in &self.cards {
|
||||||
|
let number: usize = card.v.x.into();
|
||||||
|
let shading: usize = card.v.y.into();
|
||||||
|
let color: usize = card.v.z.into();
|
||||||
|
let shape: usize = card.v.w.into();
|
||||||
|
grid[number][shading][color][shape] = true;
|
||||||
|
}
|
||||||
|
grid
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn score(&self) -> f32 {
|
||||||
|
let grid = self.grid();
|
||||||
|
let mut bins = [[[[0u8; 3]; 3]; 3]; 4];
|
||||||
|
for number in 0..3 {
|
||||||
|
for shading in 0..3 {
|
||||||
|
for color in 0..3 {
|
||||||
|
for shape in 0..3 {
|
||||||
|
if grid[number][shading][color][shape] {
|
||||||
|
bins[0][number][shading][color] += 1;
|
||||||
|
bins[1][number][shading][shape] += 1;
|
||||||
|
bins[2][number][color][shape] += 1;
|
||||||
|
bins[3][shading][color][shape] += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut score = 0f32;
|
||||||
|
for bin in bins.as_flattened().as_flattened().as_flattened() {
|
||||||
|
if !bin.is_zero() {
|
||||||
|
let p = f32::from(*bin) / 20.0;
|
||||||
|
score -= p * f32::log2(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
score
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn print_grid(&self) {
|
||||||
|
let grid = self.grid();
|
||||||
|
println!("+---+---+---+");
|
||||||
|
for number in 0..3 {
|
||||||
|
for color in 0..3 {
|
||||||
|
print!("|");
|
||||||
|
for shading in 0..3 {
|
||||||
|
for shape in 0..3 {
|
||||||
|
if grid[number][shading][color][shape] {
|
||||||
|
print!("X");
|
||||||
|
} else {
|
||||||
|
print!(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
print!("|");
|
||||||
|
}
|
||||||
|
println!("");
|
||||||
|
}
|
||||||
|
println!("+---+---+---+");
|
||||||
|
}
|
||||||
|
println!("score: {}", self.score());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CardMapping {
|
||||||
|
m: Matrix4<F3>,
|
||||||
|
v: Vector4<F3>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CardMapping {
|
||||||
|
pub fn map_single(&self, card: Card) -> Card {
|
||||||
|
Card {
|
||||||
|
v: self.m * card.v + self.v,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn map(&self, cs: CardSet) -> CardSet {
|
||||||
|
CardSet {
|
||||||
|
cards: cs
|
||||||
|
.cards
|
||||||
|
.into_iter()
|
||||||
|
.map(|card| self.map_single(card))
|
||||||
|
.collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Matrix4::determinant() only works for floating point types :(
|
||||||
|
fn determinant(m: &Matrix4<F3>) -> F3 {
|
||||||
|
let d_12 = m.m33 * m.m44 - m.m43 * m.m34;
|
||||||
|
let d_13 = m.m23 * m.m44 - m.m43 * m.m24;
|
||||||
|
let d_14 = m.m23 * m.m34 - m.m33 * m.m24;
|
||||||
|
let d_23 = m.m13 * m.m44 - m.m43 * m.m14;
|
||||||
|
let d_24 = m.m13 * m.m34 - m.m33 * m.m14;
|
||||||
|
let d_34 = m.m13 * m.m24 - m.m23 * m.m14;
|
||||||
|
let d_1 = m.m22 * d_12 - m.m32 * d_13 + m.m42 * d_14;
|
||||||
|
let d_2 = m.m12 * d_12 - m.m32 * d_23 + m.m42 * d_24;
|
||||||
|
let d_3 = m.m12 * d_13 - m.m22 * d_23 + m.m42 * d_34;
|
||||||
|
let d_4 = m.m12 * d_14 - m.m22 * d_24 + m.m32 * d_34;
|
||||||
|
m.m11 * d_1 - m.m21 * d_2 + m.m31 * d_3 - m.m41 * d_4
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Distribution<CardMapping> for StandardUniform {
|
||||||
|
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> CardMapping {
|
||||||
|
loop {
|
||||||
|
let m = Matrix4::<F3>::from_fn(|_, _| rng.random());
|
||||||
|
if !determinant(&m).is_zero() {
|
||||||
|
return CardMapping {
|
||||||
|
m: m,
|
||||||
|
v: Vector4::<F3>::from_fn(|_, _| rng.random()),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use rand::rng;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mapping_invertable() {
|
||||||
|
let mut rng = rng();
|
||||||
|
for _ in 0..1000 {
|
||||||
|
let mapping: CardMapping = rng.sample(StandardUniform);
|
||||||
|
for i in 0..3u8.pow(4) {
|
||||||
|
let card = Card::new(i / 3 / 3 / 3, i / 3 / 3 % 3, i / 3 % 3, i % 3);
|
||||||
|
if !card.v.is_zero() {
|
||||||
|
assert_ne!(mapping.map_single(card).v, mapping.v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
236
src/f3.rs
Normal file
236
src/f3.rs
Normal file
|
|
@ -0,0 +1,236 @@
|
||||||
|
use num::traits::{One, Zero};
|
||||||
|
use rand::distr::{Distribution, StandardUniform};
|
||||||
|
use rand::Rng;
|
||||||
|
use std::ops::{Add, AddAssign, Mul, MulAssign, Sub, SubAssign};
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||||
|
pub struct F3 {
|
||||||
|
s: i8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl F3 {
|
||||||
|
pub const ELEMENTS: [F3; 3] = [F3 { s: 0 }, F3 { s: 1 }, F3 { s: 2 }];
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<F3> for usize {
|
||||||
|
fn from(f: F3) -> usize {
|
||||||
|
f.s as usize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<u8> for F3 {
|
||||||
|
type Error = &'static str;
|
||||||
|
|
||||||
|
fn try_from(i: u8) -> Result<Self, Self::Error> {
|
||||||
|
if i > 2 {
|
||||||
|
Err("out of range")
|
||||||
|
} else {
|
||||||
|
Ok(F3 { s: i as i8 })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add for F3 {
|
||||||
|
type Output = F3;
|
||||||
|
|
||||||
|
fn add(self, rhs: Self) -> Self::Output {
|
||||||
|
F3 {
|
||||||
|
s: (self.s + rhs.s).rem_euclid(3),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AddAssign for F3 {
|
||||||
|
fn add_assign(&mut self, rhs: Self) {
|
||||||
|
*self = *self + rhs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Zero for F3 {
|
||||||
|
fn zero() -> Self {
|
||||||
|
F3 { s: 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_zero(&self) -> bool {
|
||||||
|
*self == Self::zero()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sub for F3 {
|
||||||
|
type Output = F3;
|
||||||
|
|
||||||
|
fn sub(self, rhs: Self) -> Self::Output {
|
||||||
|
F3 {
|
||||||
|
s: (self.s - rhs.s).rem_euclid(3),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SubAssign for F3 {
|
||||||
|
fn sub_assign(&mut self, rhs: Self) {
|
||||||
|
*self = *self - rhs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mul for F3 {
|
||||||
|
type Output = F3;
|
||||||
|
|
||||||
|
fn mul(self, rhs: Self) -> Self::Output {
|
||||||
|
F3 {
|
||||||
|
s: (self.s * rhs.s).rem_euclid(3),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MulAssign for F3 {
|
||||||
|
fn mul_assign(&mut self, rhs: Self) {
|
||||||
|
*self = *self * rhs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl One for F3 {
|
||||||
|
fn one() -> Self {
|
||||||
|
F3 { s: 1 }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_one(&self) -> bool {
|
||||||
|
*self == Self::one()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Distribution<F3> for StandardUniform {
|
||||||
|
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> F3 {
|
||||||
|
F3 {
|
||||||
|
s: rng.random_range(0..3),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_associative() {
|
||||||
|
for a in F3::ELEMENTS {
|
||||||
|
for b in F3::ELEMENTS {
|
||||||
|
for c in F3::ELEMENTS {
|
||||||
|
assert_eq!((a + b) + c, a + (b + c));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_identity() {
|
||||||
|
for a in F3::ELEMENTS {
|
||||||
|
assert_eq!(F3::zero() + a, a);
|
||||||
|
assert_eq!(a + F3::zero(), a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_inverse() {
|
||||||
|
for a in F3::ELEMENTS {
|
||||||
|
let mut has_inverse = false;
|
||||||
|
for b in F3::ELEMENTS {
|
||||||
|
if a + b == F3::zero() {
|
||||||
|
assert!(!has_inverse);
|
||||||
|
has_inverse = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert!(has_inverse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sub_is_add_inverse() {
|
||||||
|
for a in F3::ELEMENTS {
|
||||||
|
for b in F3::ELEMENTS {
|
||||||
|
assert_eq!(a + b - b, a);
|
||||||
|
assert_eq!(a - b + b, a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_commutative() {
|
||||||
|
for a in F3::ELEMENTS {
|
||||||
|
for b in F3::ELEMENTS {
|
||||||
|
assert_eq!(a + b, b + a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mul_associative() {
|
||||||
|
for a in F3::ELEMENTS {
|
||||||
|
for b in F3::ELEMENTS {
|
||||||
|
for c in F3::ELEMENTS {
|
||||||
|
assert_eq!((a * b) * c, a * (b * c));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mul_identity() {
|
||||||
|
for a in F3::ELEMENTS {
|
||||||
|
assert_eq!(F3::one() * a, a);
|
||||||
|
assert_eq!(a * F3::one(), a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mul_inverse() {
|
||||||
|
for a in F3::ELEMENTS {
|
||||||
|
if !a.is_zero() {
|
||||||
|
let mut has_inverse = false;
|
||||||
|
for b in F3::ELEMENTS {
|
||||||
|
if a * b == F3::one() {
|
||||||
|
assert!(!has_inverse);
|
||||||
|
has_inverse = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert!(has_inverse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mul_commutative() {
|
||||||
|
for a in F3::ELEMENTS {
|
||||||
|
for b in F3::ELEMENTS {
|
||||||
|
assert_eq!(a * b, b * a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn distributive() {
|
||||||
|
for a in F3::ELEMENTS {
|
||||||
|
for b in F3::ELEMENTS {
|
||||||
|
for c in F3::ELEMENTS {
|
||||||
|
assert_eq!(a * (b + c), a * b + a * c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_is_like_set() {
|
||||||
|
let e = F3::ELEMENTS;
|
||||||
|
|
||||||
|
assert_eq!(e[0] + e[0] + e[0], F3::zero());
|
||||||
|
assert_eq!(e[1] + e[1] + e[1], F3::zero());
|
||||||
|
assert_eq!(e[2] + e[2] + e[2], F3::zero());
|
||||||
|
assert_eq!(e[0] + e[1] + e[2], F3::zero());
|
||||||
|
|
||||||
|
assert_ne!(e[0] + e[0] + e[1], F3::zero());
|
||||||
|
assert_ne!(e[0] + e[0] + e[2], F3::zero());
|
||||||
|
assert_ne!(e[1] + e[1] + e[0], F3::zero());
|
||||||
|
assert_ne!(e[1] + e[1] + e[2], F3::zero());
|
||||||
|
assert_ne!(e[2] + e[2] + e[0], F3::zero());
|
||||||
|
assert_ne!(e[2] + e[2] + e[1], F3::zero());
|
||||||
|
}
|
||||||
|
}
|
||||||
44
src/main.rs
Normal file
44
src/main.rs
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
mod card;
|
||||||
|
mod f3;
|
||||||
|
|
||||||
|
use crate::card::{Card, CardMapping, CardSet};
|
||||||
|
use rand::distr::StandardUniform;
|
||||||
|
use rand::{rng, Rng};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut rng = rng();
|
||||||
|
let mut cards = CardSet::new(&[
|
||||||
|
Card::new(0, 0, 0, 1),
|
||||||
|
Card::new(0, 0, 1, 0),
|
||||||
|
Card::new(0, 0, 1, 2),
|
||||||
|
Card::new(0, 0, 2, 1),
|
||||||
|
Card::new(0, 1, 1, 1),
|
||||||
|
Card::new(0, 2, 0, 0),
|
||||||
|
Card::new(0, 2, 0, 2),
|
||||||
|
Card::new(0, 2, 2, 0),
|
||||||
|
Card::new(0, 2, 2, 2),
|
||||||
|
Card::new(1, 0, 1, 1),
|
||||||
|
Card::new(1, 2, 1, 1),
|
||||||
|
Card::new(2, 0, 0, 0),
|
||||||
|
Card::new(2, 0, 0, 2),
|
||||||
|
Card::new(2, 0, 2, 0),
|
||||||
|
Card::new(2, 0, 2, 2),
|
||||||
|
Card::new(2, 1, 1, 1),
|
||||||
|
Card::new(2, 2, 0, 1),
|
||||||
|
Card::new(2, 2, 1, 0),
|
||||||
|
Card::new(2, 2, 1, 2),
|
||||||
|
Card::new(2, 2, 2, 1),
|
||||||
|
]);
|
||||||
|
cards.print_grid();
|
||||||
|
|
||||||
|
let mut max_score = cards.score();
|
||||||
|
loop {
|
||||||
|
let mapping: CardMapping = rng.sample(StandardUniform);
|
||||||
|
cards = mapping.map(cards);
|
||||||
|
let score = cards.score();
|
||||||
|
if score > max_score {
|
||||||
|
max_score = score;
|
||||||
|
cards.print_grid();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue