restructured, flips working, benchmarking flips, got some basic terminal rendering
This commit is contained in:
parent
10de749e1d
commit
d7d8732904
17 changed files with 331 additions and 822 deletions
531
Cargo.lock
generated
531
Cargo.lock
generated
|
|
@ -11,12 +11,6 @@ dependencies = [
|
|||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "allocator-api2"
|
||||
version = "0.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
||||
|
||||
[[package]]
|
||||
name = "anes"
|
||||
version = "0.1.6"
|
||||
|
|
@ -29,45 +23,30 @@ version = "1.0.13"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78"
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
|
||||
|
||||
[[package]]
|
||||
name = "cassowary"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53"
|
||||
|
||||
[[package]]
|
||||
name = "cast"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
|
||||
|
||||
[[package]]
|
||||
name = "castaway"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a"
|
||||
dependencies = [
|
||||
"rustversion",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.4"
|
||||
|
|
@ -126,20 +105,6 @@ version = "0.7.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d"
|
||||
|
||||
[[package]]
|
||||
name = "compact_str"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b79c4069c6cad78e2e0cdfcbd26275770669fb39fd308a752dc110e83b9af32"
|
||||
dependencies = [
|
||||
"castaway",
|
||||
"cfg-if",
|
||||
"itoa",
|
||||
"rustversion",
|
||||
"ryu",
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "criterion"
|
||||
version = "0.7.0"
|
||||
|
|
@ -198,106 +163,18 @@ version = "0.8.21"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
|
||||
|
||||
[[package]]
|
||||
name = "crossterm"
|
||||
version = "0.28.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"crossterm_winapi",
|
||||
"mio",
|
||||
"parking_lot",
|
||||
"rustix",
|
||||
"signal-hook",
|
||||
"signal-hook-mio",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossterm_winapi"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crunchy"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.20.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"darling_macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_core"
|
||||
version = "0.20.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e"
|
||||
dependencies = [
|
||||
"fnv",
|
||||
"ident_case",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_macro"
|
||||
version = "0.20.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "foldhash"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
|
||||
|
||||
[[package]]
|
||||
name = "half"
|
||||
version = "2.7.1"
|
||||
|
|
@ -309,58 +186,6 @@ dependencies = [
|
|||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.15.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
|
||||
dependencies = [
|
||||
"allocator-api2",
|
||||
"equivalent",
|
||||
"foldhash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "iagorithms"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"neorusticus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ident_case"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||
|
||||
[[package]]
|
||||
name = "indoc"
|
||||
version = "2.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706"
|
||||
dependencies = [
|
||||
"rustversion",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "instability"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "435d80800b936787d62688c927b6490e887c7ef5ff9ce922c6c6050fca75eb9a"
|
||||
dependencies = [
|
||||
"darling",
|
||||
"indoc",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.13.0"
|
||||
|
|
@ -386,66 +211,12 @@ dependencies = [
|
|||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.177"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
|
||||
dependencies = [
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
|
||||
|
||||
[[package]]
|
||||
name = "lru"
|
||||
version = "0.12.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38"
|
||||
dependencies = [
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"wasi",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "neorusticus"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c0f887dfb09c7315d803a0ceac77f27da5c84213c9b170dc8ae88d2b6b1739a"
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
|
|
@ -471,39 +242,10 @@ checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e"
|
|||
name = "othello"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"criterion",
|
||||
"ratatui",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
"parking_lot_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.9.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"smallvec",
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
||||
|
||||
[[package]]
|
||||
name = "plotters"
|
||||
version = "0.3.7"
|
||||
|
|
@ -534,9 +276,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.102"
|
||||
version = "1.0.103"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e0f6df8eaa422d97d72edcd152e1451618fed47fabbdbd5a8864167b1d4aff7"
|
||||
checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
|
@ -550,27 +292,6 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ratatui"
|
||||
version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eabd94c2f37801c20583fc49dd5cd6b0ba68c716787c2dd6ed18571e1e63117b"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cassowary",
|
||||
"compact_str",
|
||||
"crossterm",
|
||||
"indoc",
|
||||
"instability",
|
||||
"itertools",
|
||||
"lru",
|
||||
"paste",
|
||||
"strum",
|
||||
"unicode-segmentation",
|
||||
"unicode-truncate",
|
||||
"unicode-width 0.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "1.11.0"
|
||||
|
|
@ -591,15 +312,6 @@ dependencies = [
|
|||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.5.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.12.2"
|
||||
|
|
@ -629,19 +341,6 @@ version = "0.8.8"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.22"
|
||||
|
|
@ -663,12 +362,6 @@ dependencies = [
|
|||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.228"
|
||||
|
|
@ -712,76 +405,6 @@ dependencies = [
|
|||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook"
|
||||
version = "0.3.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"signal-hook-registry",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-mio"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"mio",
|
||||
"signal-hook",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
|
||||
|
||||
[[package]]
|
||||
name = "static_assertions"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "strum"
|
||||
version = "0.26.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06"
|
||||
dependencies = [
|
||||
"strum_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strum_macros"
|
||||
version = "0.26.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustversion",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.108"
|
||||
|
|
@ -805,38 +428,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.20"
|
||||
version = "1.0.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-truncate"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3644627a5af5fa321c95b9b235a72fd24cd29c648c2c379431e6628655627bf"
|
||||
dependencies = [
|
||||
"itertools",
|
||||
"unicode-segmentation",
|
||||
"unicode-width 0.1.14",
|
||||
]
|
||||
|
||||
[[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.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd"
|
||||
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
|
|
@ -848,12 +442,6 @@ dependencies = [
|
|||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.1+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.105"
|
||||
|
|
@ -909,52 +497,21 @@ dependencies = [
|
|||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
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.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
|
||||
dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[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]]
|
||||
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.59.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.61.2"
|
||||
|
|
@ -964,70 +521,6 @@ dependencies = [
|
|||
"windows-link",
|
||||
]
|
||||
|
||||
[[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 = "zerocopy"
|
||||
version = "0.8.27"
|
||||
|
|
|
|||
29
Cargo.toml
29
Cargo.toml
|
|
@ -1,7 +1,26 @@
|
|||
[workspace]
|
||||
members = ["iagorithms", "othello"]
|
||||
[package]
|
||||
name = "othello"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[workspace.dependencies]
|
||||
neorusticus = "0.1.3"
|
||||
ratatui = "0.29.0"
|
||||
[lib]
|
||||
name = "othello"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "othello-gui"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.100"
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = "0.7.0"
|
||||
|
||||
[[bench]]
|
||||
name = "generation"
|
||||
harness = false
|
||||
|
||||
[[bench]]
|
||||
name = "reversals"
|
||||
harness = false
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use std::hint::black_box;
|
|||
use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};
|
||||
use othello::{board::BitBoard, game::Team};
|
||||
|
||||
const JONS: [&'static str; 20] = [
|
||||
const JONS: [&str; 20] = [
|
||||
"///3bw/3wb",
|
||||
"///////6bw",
|
||||
"///////wb",
|
||||
24
benches/reversals.rs
Normal file
24
benches/reversals.rs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
use std::hint::black_box;
|
||||
|
||||
use criterion::{Criterion, criterion_group, criterion_main};
|
||||
use othello::{
|
||||
board::{Board, squares::*},
|
||||
game::Game,
|
||||
};
|
||||
|
||||
const PLAYS: [Board; 15] = [F5, F4, E3, F3, G4, G5, H4, H5, E6, D3, C4, C5, D6, C6, B5];
|
||||
|
||||
fn bench_available_all_positions_sequential(c: &mut Criterion) {
|
||||
c.bench_function("play_four_move_opening", |b| {
|
||||
b.iter(|| {
|
||||
let mut game = Game::default();
|
||||
for play in PLAYS {
|
||||
black_box(game.play(play));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
criterion_group!(benches, bench_available_all_positions_sequential,);
|
||||
|
||||
criterion_main!(benches);
|
||||
1
iagorithms/.gitignore
vendored
1
iagorithms/.gitignore
vendored
|
|
@ -1 +0,0 @@
|
|||
/target
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
[package]
|
||||
name = "iagorithms"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
neorusticus.workspace = true
|
||||
|
|
@ -1,225 +0,0 @@
|
|||
use neorusticus::{PrologEngine, quick_query};
|
||||
use std::error::Error;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn init() -> Result<(), Box<dyn Error>> {
|
||||
println!("=== Neorusticus Prolog Engine Demo ===\n");
|
||||
|
||||
// Create engine with conservative limits for safety
|
||||
let mut engine = PrologEngine::with_limits(50);
|
||||
|
||||
// Test basic parsing with error handling
|
||||
println!("=== Testing Basic Operations ===");
|
||||
|
||||
// Test successful operations
|
||||
match engine.parse_and_add("parent(tom, bob).") {
|
||||
Ok(()) => println!("✓ Successfully added: parent(tom, bob)."),
|
||||
Err(e) => {
|
||||
println!("✗ Failed to add clause:");
|
||||
engine.print_error(&e);
|
||||
}
|
||||
}
|
||||
|
||||
match engine.parse_and_add("parent(bob, ann).") {
|
||||
Ok(()) => println!("✓ Successfully added: parent(bob, ann)."),
|
||||
Err(e) => {
|
||||
println!("✗ Failed to add clause:");
|
||||
engine.print_error(&e);
|
||||
}
|
||||
}
|
||||
|
||||
// Test error cases
|
||||
println!("\n=== Testing Error Handling ===");
|
||||
|
||||
// Test syntax errors
|
||||
println!("Testing syntax errors:");
|
||||
|
||||
if let Err(e) = engine.parse_and_add("parent(tom bob).") {
|
||||
// Missing comma
|
||||
println!("✓ Caught syntax error: {}", e);
|
||||
}
|
||||
|
||||
if let Err(e) = engine.parse_and_add("parent(tom, bob") {
|
||||
// Missing closing paren
|
||||
println!("✓ Caught delimiter error: {}", e);
|
||||
}
|
||||
|
||||
if let Err(e) = engine.parse_and_add("parent(tom, bob)") {
|
||||
// Missing dot
|
||||
println!("✓ Caught missing dot error: {}", e);
|
||||
}
|
||||
|
||||
if let Err(e) = engine.parse_and_add("parent(tom, 999999999999999999999).") {
|
||||
// Number too large
|
||||
println!("✓ Caught number overflow error: {}", e);
|
||||
}
|
||||
|
||||
// Test arithmetic operations with error handling
|
||||
println!("\n=== Testing Arithmetic Error Handling ===");
|
||||
|
||||
engine.parse_and_add("test_arith :- X is 5 + 3.")?;
|
||||
|
||||
// Test division by zero
|
||||
if let Err(e) = engine.parse_query("X is 5 // 0.") {
|
||||
println!("✓ Caught division by zero: {}", e);
|
||||
}
|
||||
|
||||
// Test uninstantiated variable in arithmetic
|
||||
if let Err(e) = engine.parse_query("X is Y + 1.") {
|
||||
println!("✓ Caught uninstantiated variable: {}", e);
|
||||
}
|
||||
|
||||
// Test type mismatch
|
||||
if let Err(e) = engine.parse_query("X is atom + 1.") {
|
||||
println!("✓ Caught type mismatch: {}", e);
|
||||
}
|
||||
|
||||
// Test successful arithmetic
|
||||
match engine.parse_query("X is 2 + 3 * 4.") {
|
||||
Ok(solutions) => {
|
||||
println!("✓ Arithmetic success:");
|
||||
engine.print_solutions(&solutions, &["X".to_string()]);
|
||||
}
|
||||
Err(e) => {
|
||||
println!("✗ Unexpected arithmetic error:");
|
||||
engine.print_boxed_error(&e);
|
||||
}
|
||||
}
|
||||
|
||||
// Test list operations with error handling
|
||||
println!("\n=== Testing List Error Handling ===");
|
||||
|
||||
// Test invalid list structure
|
||||
if let Err(e) = engine.parse_query("member(X, not_a_list).") {
|
||||
println!("✓ Caught invalid list structure: {}", e);
|
||||
}
|
||||
|
||||
// Test uninstantiated list
|
||||
if let Err(e) = engine.parse_query("length(L, 3).") {
|
||||
println!("✓ Caught uninstantiated list: {}", e);
|
||||
}
|
||||
|
||||
// Test successful list operations
|
||||
match engine.parse_query("append([1, 2], [3, 4], X).") {
|
||||
Ok(solutions) => {
|
||||
println!("✓ List append success:");
|
||||
engine.print_solutions(&solutions, &["X".to_string()]);
|
||||
}
|
||||
Err(e) => {
|
||||
println!("✗ Unexpected list error:");
|
||||
engine.print_boxed_error(&e);
|
||||
}
|
||||
}
|
||||
|
||||
// Test predicate suggestions
|
||||
println!("\n=== Testing Predicate Suggestions ===");
|
||||
|
||||
if let Err(e) = engine.parse_query("lentgh([1, 2, 3], X).") {
|
||||
// Typo in "length"
|
||||
println!("✓ Predicate suggestion: {}", e);
|
||||
}
|
||||
|
||||
if let Err(e) = engine.parse_query("appendd([1], [2], X).") {
|
||||
// Typo in "append"
|
||||
println!("✓ Predicate suggestion: {}", e);
|
||||
}
|
||||
|
||||
// Test stack overflow protection with a safer approach
|
||||
println!("\n=== Testing Stack Overflow Protection ===");
|
||||
|
||||
// Use a very conservative engine for this test
|
||||
let mut test_engine = PrologEngine::with_limits(5);
|
||||
|
||||
// Add the infinite recursion rule to the test engine only
|
||||
match test_engine.parse_and_add("infinite(X) :- infinite(X).") {
|
||||
Ok(_) => {
|
||||
// Now test the query with the dangerous rule
|
||||
match test_engine.parse_query("infinite(test).") {
|
||||
Ok(_) => println!("✗ Failed to catch infinite recursion"),
|
||||
Err(e) => println!("✓ Caught infinite recursion: {}", e),
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
println!("✗ Failed to add infinite rule: {}", e);
|
||||
}
|
||||
}
|
||||
|
||||
// Test cut operations
|
||||
println!("\n=== Testing Cut Operations ===");
|
||||
|
||||
engine.parse_and_add("max(X, Y, X) :- X >= Y, !.")?;
|
||||
engine.parse_and_add("max(X, Y, Y).")?;
|
||||
|
||||
match engine.parse_query("max(5, 3, Z).") {
|
||||
Ok(solutions) => {
|
||||
println!("✓ Cut operation success:");
|
||||
engine.print_solutions(&solutions, &["Z".to_string()]);
|
||||
}
|
||||
Err(e) => {
|
||||
println!("✗ Unexpected cut error:");
|
||||
engine.print_boxed_error(&e);
|
||||
}
|
||||
}
|
||||
|
||||
// Display engine statistics
|
||||
println!("\n=== Engine Statistics ===");
|
||||
println!("{}", engine.get_stats());
|
||||
|
||||
// Test complex query with multiple error possibilities
|
||||
println!("\n=== Testing Complex Query ===");
|
||||
|
||||
engine.parse_and_add("complex(X, Y) :- X > 0, Y is X * 2, Y < 20.")?;
|
||||
|
||||
match engine.parse_query("complex(5, Z).") {
|
||||
Ok(solutions) => {
|
||||
println!("✓ Complex query success:");
|
||||
engine.print_solutions(&solutions, &["Z".to_string()]);
|
||||
}
|
||||
Err(e) => {
|
||||
println!("✗ Complex query error:");
|
||||
engine.print_boxed_error(&e);
|
||||
}
|
||||
}
|
||||
|
||||
// Test recovery from errors
|
||||
println!("\n=== Testing Error Recovery ===");
|
||||
|
||||
// Even after errors, the engine should continue to work
|
||||
match engine.parse_query("parent(tom, X).") {
|
||||
Ok(solutions) => {
|
||||
println!("✓ Engine recovered, normal operation:");
|
||||
engine.print_solutions(&solutions, &["X".to_string()]);
|
||||
}
|
||||
Err(e) => {
|
||||
println!("✗ Engine failed to recover:");
|
||||
engine.print_boxed_error(&e);
|
||||
}
|
||||
}
|
||||
|
||||
// Demonstrate the quick_query convenience function
|
||||
println!("\n=== Testing Quick Query Function ===");
|
||||
|
||||
let clauses = &[
|
||||
"ancestor(X, Y) :- parent(X, Y).",
|
||||
"ancestor(X, Z) :- parent(X, Y), ancestor(Y, Z).",
|
||||
"parent(alice, bob).",
|
||||
"parent(bob, charlie).",
|
||||
"parent(charlie, diana).",
|
||||
];
|
||||
|
||||
match quick_query(clauses, "ancestor(alice, diana).") {
|
||||
Ok(solutions) => {
|
||||
println!("✓ Quick query found {} solutions", solutions.len());
|
||||
}
|
||||
Err(e) => {
|
||||
println!("✗ Quick query failed: {}", e);
|
||||
}
|
||||
}
|
||||
|
||||
println!("\n=== All tests completed ===");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
1
othello/.gitignore
vendored
1
othello/.gitignore
vendored
|
|
@ -1 +0,0 @@
|
|||
/target
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
[package]
|
||||
name = "othello"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[lib]
|
||||
name = "othello"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "othello-tui"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
ratatui.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
criterion.workspace = true
|
||||
|
||||
[[bench]]
|
||||
name = "generation"
|
||||
harness = false
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
#[repr(u8)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum Team {
|
||||
Black,
|
||||
White,
|
||||
}
|
||||
|
||||
impl Team {
|
||||
/// Just return the other team or the next team.
|
||||
/// This is useful for modeling state transfer
|
||||
pub fn next(&self) -> Self {
|
||||
match self {
|
||||
Team::Black => Team::White,
|
||||
Team::White => Team::Black,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
fn main() {
|
||||
println!("Hello, world!");
|
||||
}
|
||||
|
|
@ -3,7 +3,12 @@
|
|||
|
||||
use std::fmt::{Debug, Display};
|
||||
|
||||
use crate::game::Team;
|
||||
use crate::{
|
||||
board::view::{Overlay, View},
|
||||
game::Team,
|
||||
};
|
||||
|
||||
pub mod view;
|
||||
|
||||
pub type Board = u64;
|
||||
|
||||
|
|
@ -25,20 +30,19 @@ pub type Board = u64;
|
|||
// shifting to the left to bring it to match our current focus. Thus:
|
||||
// Positive => SHL
|
||||
// Negative => SHR
|
||||
const DIRECTIONS: [i8; 8] = [9, 8, 7, 1, -1, -7, -8, -9];
|
||||
// simply negating the A file
|
||||
const NOT_A_FILE: Board = 0x7F7F7F7F7F7F7F7F;
|
||||
// simply negating the H file
|
||||
const NOT_H_FILE: Board = 0xFEFEFEFEFEFEFEFE;
|
||||
const DIRECTION_MASKS: [Board; 8] = [
|
||||
NOT_A_FILE, // 9 (up right)
|
||||
Board::MAX, // 8 (up)
|
||||
NOT_H_FILE, // 7 (up left)
|
||||
NOT_A_FILE, // 1 (right)
|
||||
NOT_H_FILE, // -1 (left)
|
||||
NOT_A_FILE, // -7 (down right)
|
||||
Board::MAX, // -8 (down)
|
||||
NOT_H_FILE, // -9 (down left)
|
||||
const SHIFT_MASK_COMBOS: [(i8, Board); 8] = [
|
||||
(9, NOT_A_FILE), // 9 (up right)
|
||||
(8, Board::MAX), // 8 (up)
|
||||
(7, NOT_H_FILE), // 7 (up left)
|
||||
(1, NOT_A_FILE), // 1 (right)
|
||||
(-1, NOT_H_FILE), // -1 (left)
|
||||
(-7, NOT_A_FILE), // -7 (down right)
|
||||
(-8, Board::MAX), // -8 (down)
|
||||
(-9, NOT_H_FILE), // -9 (down left)
|
||||
];
|
||||
|
||||
/// Represents the board state using two integers. This allows us to reduce the
|
||||
|
|
@ -75,10 +79,11 @@ const DIRECTION_MASKS: [Board; 8] = [
|
|||
/// and files are to be rendered or oriented due to the symmetrical nature
|
||||
/// of Othello, but I stick to rigid Chess-esque conventions for the sake of my
|
||||
/// sanity.
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
pub struct BitBoard {
|
||||
/// Contains all boards for game. In this case, there are only two.
|
||||
/// The first is black. The second is white.
|
||||
boards: [Board; 2],
|
||||
pub boards: [Board; 2],
|
||||
}
|
||||
|
||||
impl Default for BitBoard {
|
||||
|
|
@ -131,7 +136,7 @@ impl Display for BitBoard {
|
|||
.unwrap();
|
||||
}
|
||||
if r != 0 {
|
||||
write!(f, "\n").unwrap();
|
||||
writeln!(f).unwrap();
|
||||
}
|
||||
}
|
||||
write!(f, "\n abcdefgh").unwrap();
|
||||
|
|
@ -141,15 +146,21 @@ impl Display for BitBoard {
|
|||
|
||||
fn shift_in_direction(magnitude: i8, value: Board) -> Board {
|
||||
if magnitude >= 0 {
|
||||
let (result, _) = value.overflowing_shl(magnitude.abs() as u32);
|
||||
let (result, _) = value.overflowing_shl(magnitude.unsigned_abs() as u32);
|
||||
result
|
||||
} else {
|
||||
let (result, _) = value.overflowing_shr(magnitude.abs() as u32);
|
||||
let (result, _) = value.overflowing_shr(magnitude.unsigned_abs() as u32);
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl BitBoard {
|
||||
/// Create a new BitBoard from provided team boards.
|
||||
pub fn new(black: Board, white: Board) -> Self {
|
||||
Self {
|
||||
boards: [black, white],
|
||||
}
|
||||
}
|
||||
/// Convert from a JON (Jack Othello Notation) string into a usable board.
|
||||
/// Format:
|
||||
///
|
||||
|
|
@ -170,7 +181,7 @@ impl BitBoard {
|
|||
let mut line: u8 = 7;
|
||||
let mut rank_idx: u8 = 0;
|
||||
let mut rank_jump: u8 = 0;
|
||||
for c in fen.chars().into_iter() {
|
||||
for c in fen.chars() {
|
||||
match c.to_ascii_lowercase() {
|
||||
'/' => {
|
||||
line = line.checked_sub(1).ok_or("Malformed JON: Too many ranks")?;
|
||||
|
|
@ -187,7 +198,7 @@ impl BitBoard {
|
|||
rank_idx += rank_jump + 1;
|
||||
rank_jump = 0;
|
||||
}
|
||||
'0'..'9' => {
|
||||
'0'..='8' => {
|
||||
rank_jump = c
|
||||
.to_digit(10u32)
|
||||
.ok_or("JON Parsing error: Failed to parse integer from character")?
|
||||
|
|
@ -203,6 +214,16 @@ impl BitBoard {
|
|||
}
|
||||
Ok(Self { boards })
|
||||
}
|
||||
|
||||
pub fn player_at(&self, rank: u8, file: u8) -> Option<Team> {
|
||||
if self.boards[0] & (1 << (rank * 8 + file)) != 0 {
|
||||
Some(Team::Black)
|
||||
} else if self.boards[1] & (1 << (rank * 8 + file)) != 0 {
|
||||
Some(Team::White)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
/// Compute board with valid moves marked using only bitwise operations.
|
||||
/// This has constant time complexity and is unbelievably fast.
|
||||
pub fn available(&self, current_team: Team) -> Board {
|
||||
|
|
@ -262,9 +283,7 @@ impl BitBoard {
|
|||
// in an orientation such that a disc in the _a_ file is flanked on its
|
||||
// right side. We do the same for when looking left with the _h_ file.
|
||||
|
||||
for i in 0..8 {
|
||||
let shift = DIRECTIONS[i];
|
||||
let mask = DIRECTION_MASKS[i];
|
||||
for (shift, mask) in SHIFT_MASK_COMBOS {
|
||||
// begin performing masks based on where opponent positions are
|
||||
// since we can flank multiple pieces in a single direction, we
|
||||
// apply this logic seven times as this would account for the
|
||||
|
|
@ -281,9 +300,96 @@ impl BitBoard {
|
|||
|
||||
moves
|
||||
}
|
||||
|
||||
pub fn render(&self, view: impl Into<View>, overlays: Vec<Overlay>) -> String {
|
||||
let view: View = view.into();
|
||||
let mut result = String::new();
|
||||
|
||||
let raw_r_range = 0..8;
|
||||
let r_range = match view {
|
||||
View::RankAsc => Box::new(raw_r_range) as Box<dyn Iterator<Item = i32>>,
|
||||
View::RankDesc => Box::new(raw_r_range.rev()) as Box<dyn Iterator<Item = i32>>,
|
||||
};
|
||||
|
||||
for (r_idx, r) in r_range.enumerate() {
|
||||
let start_i = r * 8;
|
||||
result.push_str(&format!("{}: ", r + 1));
|
||||
for i in start_i..(start_i + 8) {
|
||||
// rshift to cut off bits on rhs, then AND on 1 to get just the last bit.
|
||||
result.push_str(&format!(
|
||||
"\x1b[42m{} \x1b[0m",
|
||||
if (self.boards[0] >> i) & 1 == 1 {
|
||||
String::from("\x1b[30m●")
|
||||
} else if (self.boards[1] >> i) & 1 == 1 {
|
||||
String::from("\x1b[97m●")
|
||||
} else {
|
||||
// if our overlay provides a character for the square, use it.
|
||||
// otherwise use the default char '-'
|
||||
overlays
|
||||
.iter()
|
||||
.find(|Overlay(board, _)| (board >> i) & 1 == 1)
|
||||
.map(|Overlay(_, c)| *c)
|
||||
.unwrap_or("░")
|
||||
.to_owned()
|
||||
}
|
||||
));
|
||||
}
|
||||
if r_idx != 7 {
|
||||
result.push('\n');
|
||||
}
|
||||
}
|
||||
result.push_str("\n a b c d e f g h");
|
||||
|
||||
result
|
||||
}
|
||||
/// Apply play to a board and compute effected reversals
|
||||
pub fn play(&mut self, current_team: Team, play: Board) {
|
||||
// bitwise OR gives spots with either white OR black discs
|
||||
// bitwise NEG gives the spots with neither white nor black discs
|
||||
let mut flips = 0;
|
||||
let current_team_idx = current_team as usize;
|
||||
let (team, opponent) = (
|
||||
self.boards[current_team_idx],
|
||||
self.boards[current_team.next() as usize],
|
||||
);
|
||||
|
||||
// For each (shift, mask) pair, check whether there's an opponent disc in
|
||||
// the direction of the shift. We mask with `mask` before shifting to avoid
|
||||
// wrapping horizontally around the edges of the board. We do this six times
|
||||
// since the maximum amount of flipped discs is six. After we're finished
|
||||
// shifting, we shift once more with the same rules and then check if we
|
||||
// intersect with a disc of our own by comparing the bitwise conjunction to
|
||||
// zero. If it's greater than zero, then we've definitely detected a() flip(s)
|
||||
// in that direction. We then add these to our running summation of flips.
|
||||
|
||||
for (shift, mask) in SHIFT_MASK_COMBOS {
|
||||
let mut flip = shift_in_direction(shift, play & mask) & opponent;
|
||||
flip |= shift_in_direction(shift, flip & mask) & opponent;
|
||||
flip |= shift_in_direction(shift, flip & mask) & opponent;
|
||||
flip |= shift_in_direction(shift, flip & mask) & opponent;
|
||||
flip |= shift_in_direction(shift, flip & mask) & opponent;
|
||||
flip |= shift_in_direction(shift, flip & mask) & opponent;
|
||||
if shift_in_direction(shift, flip & mask) & team > 0 {
|
||||
flips |= flip;
|
||||
}
|
||||
}
|
||||
|
||||
mod squares {
|
||||
self.boards[current_team_idx] += flips;
|
||||
self.boards[current_team.next() as usize] ^= flips;
|
||||
|
||||
self.boards[current_team_idx] += play;
|
||||
}
|
||||
|
||||
/// Compute the score (B, W) by counting the excited bits in each board.
|
||||
pub fn score(&self) -> (u32, u32) {
|
||||
// `u64::count_ones()` is implemented `unsafe` and makes use of primitives in the
|
||||
// low-level implementation of the language itself for maximum performance. Better
|
||||
// to use this than implement myself.
|
||||
(self.boards[0].count_ones(), self.boards[1].count_ones())
|
||||
}
|
||||
}
|
||||
|
||||
pub mod squares {
|
||||
/// Just allows us to easily define squares in terms of their shift
|
||||
macro_rules! bitboard_consts {
|
||||
($($name:ident = $digit:expr), * $(,)?) => {
|
||||
|
|
@ -577,4 +683,28 @@ mod tests {
|
|||
let bb = BitBoard::from_jon("6wb").expect("Valid board");
|
||||
assert_eq!(bb.available(Team::Black), F8);
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn render_dbg(board: BitBoard) -> BitBoard {
|
||||
println!("dbg:\n{}", board.render(View::RankAsc, vec![]));
|
||||
board
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn play_works() {
|
||||
let mut bb = BitBoard::default();
|
||||
assert_eq!(bb.score(), (2, 2));
|
||||
bb.play(Team::Black, E6);
|
||||
assert_eq!(bb, BitBoard::new(D5 | E6 | E5 | E4, D4));
|
||||
assert_eq!(bb.score(), (4, 1));
|
||||
bb.play(Team::White, F4);
|
||||
assert_eq!(bb, BitBoard::new(D5 | E6 | E5, D4 | E4 | F4));
|
||||
assert_eq!(bb.score(), (3, 3));
|
||||
bb.play(Team::Black, G3);
|
||||
assert_eq!(bb, BitBoard::new(D5 | E6 | E5 | G3 | F4, D4 | E4));
|
||||
assert_eq!(bb.score(), (5, 2));
|
||||
bb.play(Team::White, E7);
|
||||
assert_eq!(bb, BitBoard::new(D5 | G3 | F4, D4 | E4 | E5 | E6 | E7));
|
||||
assert_eq!(bb.score(), (3, 5));
|
||||
}
|
||||
}
|
||||
17
src/board/view.rs
Normal file
17
src/board/view.rs
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
use crate::{board::Board, game::Team};
|
||||
|
||||
pub enum View {
|
||||
RankAsc,
|
||||
RankDesc,
|
||||
}
|
||||
|
||||
impl From<Team> for View {
|
||||
fn from(value: Team) -> Self {
|
||||
match value {
|
||||
Team::Black => View::RankDesc,
|
||||
Team::White => View::RankAsc,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Overlay(pub Board, pub &'static str);
|
||||
30
src/cli/mod.rs
Normal file
30
src/cli/mod.rs
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
use othello::{board::view::Overlay, game::Game};
|
||||
|
||||
pub fn run() -> anyhow::Result<()> {
|
||||
let mut game = Game::default();
|
||||
|
||||
println!(
|
||||
"{}",
|
||||
game.board().render(
|
||||
game.current_team,
|
||||
vec![Overlay(
|
||||
game.board().available(game.current_team),
|
||||
"\x1b[95m*\x1b[37m"
|
||||
)]
|
||||
)
|
||||
);
|
||||
game.play(othello::board::squares::E6);
|
||||
println!();
|
||||
println!(
|
||||
"{}",
|
||||
game.board().render(
|
||||
game.current_team,
|
||||
vec![Overlay(
|
||||
game.board().available(game.current_team),
|
||||
"\x1b[34m*\x1b[37m"
|
||||
)]
|
||||
)
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
67
src/game.rs
Normal file
67
src/game.rs
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
use crate::board::{BitBoard, Board};
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Default)]
|
||||
pub enum Team {
|
||||
#[default]
|
||||
Black,
|
||||
White,
|
||||
}
|
||||
|
||||
impl Team {
|
||||
/// Just return the other team or the next team.
|
||||
/// This is useful for modeling state transfer
|
||||
pub fn next(&self) -> Self {
|
||||
match self {
|
||||
Team::Black => Team::White,
|
||||
Team::White => Team::Black,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Game {
|
||||
pub current_team: Team,
|
||||
board: BitBoard,
|
||||
}
|
||||
|
||||
impl Game {
|
||||
/// Play a move. Automatically transitions state to next player.
|
||||
pub fn play(&mut self, player_move: Board) {
|
||||
self.board.play(self.current_team, player_move);
|
||||
self.current_team = self.current_team.next();
|
||||
}
|
||||
|
||||
/// Play a move but first verify that the move is legal.
|
||||
/// Automatically transitions state to next player.
|
||||
pub fn safe_play(&mut self, player_move: Board) {
|
||||
// TODO: validate that move is legal
|
||||
self.play(player_move);
|
||||
}
|
||||
|
||||
pub fn board(&self) -> BitBoard {
|
||||
self.board
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::board::squares::*;
|
||||
#[test]
|
||||
fn play_switches_team() {
|
||||
let mut game = Game::default();
|
||||
assert_eq!(game.current_team, Team::Black);
|
||||
game.play(E6);
|
||||
assert_eq!(game.current_team, Team::White);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn play_mutates_boards() {
|
||||
let mut game = Game::default();
|
||||
let [og_b, og_w] = game.board().boards;
|
||||
game.play(E6);
|
||||
assert_ne!(og_b, game.board().boards[0]);
|
||||
assert_ne!(og_w, game.board().boards[1]);
|
||||
}
|
||||
}
|
||||
5
src/main.rs
Normal file
5
src/main.rs
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
mod cli;
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
cli::run()
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue