init
This commit is contained in:
commit
0de67fd423
13 changed files with 1263 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
target
|
||||
612
Cargo.lock
generated
Normal file
612
Cargo.lock
generated
Normal file
|
|
@ -0,0 +1,612 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "allocator-api2"
|
||||
version = "0.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
|
||||
|
||||
[[package]]
|
||||
name = "cassowary"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53"
|
||||
|
||||
[[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"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||
|
||||
[[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 = "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 = "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 = "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"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
||||
|
||||
[[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 = "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 = "othello"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"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 = "proc-macro2"
|
||||
version = "1.0.102"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e0f6df8eaa422d97d72edcd152e1451618fed47fabbdbd5a8864167b1d4aff7"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1"
|
||||
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 = "redox_syscall"
|
||||
version = "0.5.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[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"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||
|
||||
[[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"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.20"
|
||||
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"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.1+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
||||
|
||||
[[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-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"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
|
||||
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"
|
||||
6
Cargo.toml
Normal file
6
Cargo.toml
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
[workspace]
|
||||
members = ["iagorithms", "othello"]
|
||||
|
||||
[workspace.dependencies]
|
||||
neorusticus = "0.1.3"
|
||||
ratatui = "0.29.0"
|
||||
20
README.md
Normal file
20
README.md
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
# Othello
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
├── iagorithms <-- contains expert system AI library
|
||||
│ └── ...
|
||||
├── othello <-- contains main binary and library for Othello
|
||||
│ └── ...
|
||||
└── README.md <-- you are here
|
||||
```
|
||||
|
||||
## Game Representation
|
||||
|
||||
The game state is represented by what's known as a
|
||||
[BitBoard](https://www.chessprogramming.org/Bitboards). I knew about these
|
||||
already from researching Chess programming in the past.
|
||||
|
||||
This does mean that when calling upon iagorithms' it will need to _explode_
|
||||
the bitboard into a format that can be pattern matched on.
|
||||
1
iagorithms/.gitignore
vendored
Normal file
1
iagorithms/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/target
|
||||
7
iagorithms/Cargo.toml
Normal file
7
iagorithms/Cargo.toml
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
[package]
|
||||
name = "iagorithms"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
neorusticus.workspace = true
|
||||
226
iagorithms/src/lib.rs
Normal file
226
iagorithms/src/lib.rs
Normal file
|
|
@ -0,0 +1,226 @@
|
|||
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 ===");
|
||||
panic!();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
1
othello/.gitignore
vendored
Normal file
1
othello/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/target
|
||||
15
othello/Cargo.toml
Normal file
15
othello/Cargo.toml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
[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
|
||||
363
othello/src/board.rs
Normal file
363
othello/src/board.rs
Normal file
|
|
@ -0,0 +1,363 @@
|
|||
//! All things to do with the Othello game board. This module contains types,
|
||||
//! traits, and functions for working with the board.
|
||||
|
||||
use std::fmt::{Debug, Display};
|
||||
|
||||
use crate::game::Team;
|
||||
|
||||
pub type Board = u64;
|
||||
|
||||
// Directions:
|
||||
// 7 8 9
|
||||
// -1 0 1
|
||||
// -9 -8 -7
|
||||
//
|
||||
// 0 is where "we" are. The other numbers represent the index shifts to access
|
||||
// both orthogonal and diagonal adjecent squares.
|
||||
//
|
||||
// Note that negative numbers indicate a shift to the right while positive ones
|
||||
// indicate a left shift.
|
||||
//
|
||||
// When we want to shift from a higher place to a lower place (when looking
|
||||
// straight to the right or up in any direction for example), we aren't really
|
||||
// moving toward _it_. It's more so that we're moving that toward us. So a
|
||||
// digit further along in the structure (positive numbers) will require
|
||||
// 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)
|
||||
];
|
||||
|
||||
/// Represents the board state using two integers. This allows us to reduce the
|
||||
/// memory footprint by 75% when compared against using a byte[8][8] (64
|
||||
/// bytes). While digits in these boards do not have _place value_ per se, it
|
||||
/// still may be helpful to think of the structure as being Little Endian and
|
||||
/// by that I mean to say that a0 is the leftmost bit and h8 is the rightmost.
|
||||
///
|
||||
/// The values are to be mapped as follows where each number indicates the bit
|
||||
/// in the integer that corresponds to the position in the board:
|
||||
///
|
||||
/// ```text
|
||||
/// a: b: c: d: e: f: g: h:
|
||||
/// 8: 56 57 58 59 60 61 62 63 :8
|
||||
/// 7: 48 49 50 51 52 53 54 55 :7
|
||||
/// 6: 40 41 42 43 44 45 46 47 :6
|
||||
/// 5: 32 33 34 35 36 37 38 39 :5
|
||||
/// 4: 24 25 26 27 28 29 30 31 :4
|
||||
/// 3: 16 17 18 19 20 21 22 23 :3
|
||||
/// 2: 08 09 10 11 12 13 14 15 :2
|
||||
/// 1: 00 01 02 03 04 05 06 07 :1
|
||||
/// a: b: c: d: e: f: g: h:
|
||||
///
|
||||
/// =
|
||||
///
|
||||
/// bits: 00 01 ... 07 08 09 ... 15 ... 56 57 ... 63
|
||||
/// board: a1 b1 ... h1 a2 b2 ... h2 ... a8 b8 ... h8
|
||||
/// ```
|
||||
///
|
||||
/// Note that I use the traditional nomenclature of ranks and files which
|
||||
/// correspond to rows and columns respectively.
|
||||
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],
|
||||
}
|
||||
|
||||
impl Default for BitBoard {
|
||||
fn default() -> Self {
|
||||
// Create board in standard starting structure
|
||||
Self {
|
||||
boards: [(1 << 36) + (1 << 27), (1 << 35) + (1 << 28)],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for BitBoard {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("BitBoard")
|
||||
.field("black", &format!("0x{:X}", &self.boards[0]))
|
||||
.field("white", &format!("0x{:X}", &self.boards[1]))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for BitBoard {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
for r in (0..8).rev() {
|
||||
let start_i = r * 8;
|
||||
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.
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
if (self.boards[0] >> i) & 1 == 1 {
|
||||
'B'
|
||||
} else if (self.boards[1] >> i) & 1 == 1 {
|
||||
'W'
|
||||
} else {
|
||||
'-'
|
||||
}
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
if r != 0 {
|
||||
write!(f, "\n").unwrap();
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn shift_in_direction(magnitude: i8, value: Board) -> Board {
|
||||
if magnitude >= 0 {
|
||||
let (result, _) = value.overflowing_shl(magnitude.abs() as u32);
|
||||
result
|
||||
} else {
|
||||
let (result, _) = value.overflowing_shr(magnitude.abs() as u32);
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl BitBoard {
|
||||
/// Compute board with valid moves marked
|
||||
pub fn available(&self, current_team: Team) -> Board {
|
||||
// bitwise OR gives spots with either white OR black discs
|
||||
// bitwise NEG gives the spots with neither white nor black discs
|
||||
let empties = !(self.boards[0] | self.boards[1]);
|
||||
let mut moves = 0;
|
||||
let (team, opponent) = (
|
||||
self.boards[current_team as usize],
|
||||
self.boards[(current_team as usize + 1) % 2],
|
||||
);
|
||||
|
||||
// Instead of looping through a structure and checking adjacent
|
||||
// squares, we are able to rather easily aggregate these operations
|
||||
// into a handful of bitwise operations. So for example, let's
|
||||
// consider the starting board (illustrations omitting some
|
||||
// unimportant ranks):
|
||||
//
|
||||
// Game Black White
|
||||
// -------- -------- --------
|
||||
// ---WB--- = ----B--- + ---W----
|
||||
// ---BW--- ---B---- ----W---
|
||||
// -------- -------- --------
|
||||
//
|
||||
// It's black's turn. Let's first consider how we might find any
|
||||
// white pieces that are adjacent to black pieces. Let's just check
|
||||
// for white pieces that are to the _right_ of black ones. We can do
|
||||
// this by shifting all black digits to the left once (see info about
|
||||
// shifts and directions earlier in module).
|
||||
//
|
||||
// Black << 1 =
|
||||
// --------
|
||||
// -----B--
|
||||
// ----B---
|
||||
// --------
|
||||
//
|
||||
// We can then find where this shifted board intersects with white's
|
||||
// board using bitwise AND.
|
||||
//
|
||||
// Black<<1 & White = Right-adjacents (A)
|
||||
//
|
||||
// -------- -------- --------
|
||||
// -----B-- & ---W---- = --------
|
||||
// ----B--- ----W--- ----A---
|
||||
// -------- -------- --------
|
||||
//
|
||||
// We now have all the white matrices to the right of black matrices.
|
||||
// We can continue doing this in different directions using different
|
||||
// values to shift with (they are the same every time), using masks
|
||||
// here and there to avoid problems with the outer files, and then
|
||||
// bitwise OR-ing these together to get a matrix containing all
|
||||
// adjacencies.
|
||||
//
|
||||
// Certain shifts are associated with particular masks by matching
|
||||
// indices. So for example, when we're looking to the right, we want to
|
||||
// ignore the _h_ file. This is because there's no way of placing a piece
|
||||
// in an orientation such that a piece in the _h_ file is flanked on its
|
||||
// right side since the board ends. We do the same for when looking
|
||||
// left with the _a_ file.
|
||||
|
||||
for i in 0..8 {
|
||||
let shift = DIRECTIONS[i];
|
||||
let mask = DIRECTION_MASKS[i];
|
||||
// begin performing masks based on where opponent positions are
|
||||
let mut sub_move = shift_in_direction(shift, team & mask) & opponent;
|
||||
sub_move |= shift_in_direction(shift, sub_move & mask) & opponent;
|
||||
sub_move |= shift_in_direction(shift, sub_move & mask) & opponent;
|
||||
sub_move |= shift_in_direction(shift, sub_move & mask) & opponent;
|
||||
sub_move |= shift_in_direction(shift, sub_move & mask) & opponent;
|
||||
sub_move |= shift_in_direction(shift, sub_move & mask) & opponent;
|
||||
sub_move = shift_in_direction(shift, sub_move & mask) & empties;
|
||||
moves |= sub_move;
|
||||
}
|
||||
|
||||
moves
|
||||
}
|
||||
}
|
||||
|
||||
mod squares {
|
||||
/// Just allows us to easily define squares in terms of their shift
|
||||
macro_rules! bitboard_consts {
|
||||
($($name:ident = $digit:expr), * $(,)?) => {
|
||||
$(#[allow(dead_code)] pub const $name: super::Board = 1 << $digit;)*
|
||||
};
|
||||
}
|
||||
|
||||
bitboard_consts!(
|
||||
A1 = 0,
|
||||
B1 = 1,
|
||||
C1 = 2,
|
||||
D1 = 3,
|
||||
E1 = 4,
|
||||
F1 = 5,
|
||||
G1 = 6,
|
||||
H1 = 7,
|
||||
A2 = 8,
|
||||
B2 = 9,
|
||||
C2 = 10,
|
||||
D2 = 11,
|
||||
E2 = 12,
|
||||
F2 = 13,
|
||||
G2 = 14,
|
||||
H2 = 15,
|
||||
A3 = 16,
|
||||
B3 = 17,
|
||||
C3 = 18,
|
||||
D3 = 19,
|
||||
E3 = 20,
|
||||
F3 = 21,
|
||||
G3 = 22,
|
||||
H3 = 23,
|
||||
A4 = 24,
|
||||
B4 = 25,
|
||||
C4 = 26,
|
||||
D4 = 27,
|
||||
E4 = 28,
|
||||
F4 = 29,
|
||||
G4 = 30,
|
||||
H4 = 31,
|
||||
A5 = 32,
|
||||
B5 = 33,
|
||||
C5 = 34,
|
||||
D5 = 35,
|
||||
E5 = 36,
|
||||
F5 = 37,
|
||||
G5 = 38,
|
||||
H5 = 39,
|
||||
A6 = 40,
|
||||
B6 = 41,
|
||||
C6 = 42,
|
||||
D6 = 43,
|
||||
E6 = 44,
|
||||
F6 = 45,
|
||||
G6 = 46,
|
||||
H6 = 47,
|
||||
A7 = 48,
|
||||
B7 = 49,
|
||||
C7 = 50,
|
||||
D7 = 51,
|
||||
E7 = 52,
|
||||
F7 = 53,
|
||||
G7 = 54,
|
||||
H7 = 55,
|
||||
A8 = 56,
|
||||
B8 = 57,
|
||||
C8 = 58,
|
||||
D8 = 59,
|
||||
E8 = 60,
|
||||
F8 = 61,
|
||||
G8 = 62,
|
||||
H8 = 63,
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::squares::*;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_masking_logic() {
|
||||
// validating the tests used in the comment explaining the way we're
|
||||
// generating moves.
|
||||
let bb = BitBoard::default();
|
||||
let blk_shl = bb.boards[Team::Black as usize] << 1;
|
||||
// validate that they are shifted to the right
|
||||
assert_eq!(blk_shl, (1 << 37) + (1 << 28));
|
||||
// validate that they are shifted to the right visually
|
||||
let expected_output = r"--------
|
||||
--------
|
||||
--------
|
||||
-----B--
|
||||
----B---
|
||||
--------
|
||||
--------
|
||||
--------";
|
||||
assert_eq!(
|
||||
format!(
|
||||
"{}",
|
||||
BitBoard {
|
||||
boards: [blk_shl, 0]
|
||||
}
|
||||
),
|
||||
expected_output
|
||||
);
|
||||
|
||||
// test that we can mask with white squares.
|
||||
let matched = blk_shl & bb.boards[Team::White as usize];
|
||||
// validate that they are matching only
|
||||
assert_eq!(matched, !Board::MAX + (1 << 28));
|
||||
// validate that they match visually
|
||||
let expected_output = r"--------
|
||||
--------
|
||||
--------
|
||||
--------
|
||||
----B---
|
||||
--------
|
||||
--------
|
||||
--------";
|
||||
assert_eq!(
|
||||
format!(
|
||||
"{}",
|
||||
BitBoard {
|
||||
boards: [matched, 0]
|
||||
}
|
||||
),
|
||||
expected_output
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn avaliable_works() {
|
||||
let bb = BitBoard::default();
|
||||
assert_eq!(bb.available(Team::Black), D6 + C5 + F4 + E3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn display_works() {
|
||||
let bb = BitBoard::default();
|
||||
let expected_output = r"--------
|
||||
--------
|
||||
--------
|
||||
---WB---
|
||||
---BW---
|
||||
--------
|
||||
--------
|
||||
--------";
|
||||
assert_eq!(format!("{}", bb), expected_output);
|
||||
}
|
||||
}
|
||||
6
othello/src/game.rs
Normal file
6
othello/src/game.rs
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
#[repr(u8)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum Team {
|
||||
Black,
|
||||
White,
|
||||
}
|
||||
2
othello/src/lib.rs
Normal file
2
othello/src/lib.rs
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
pub mod board;
|
||||
pub mod game;
|
||||
3
othello/src/main.rs
Normal file
3
othello/src/main.rs
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
fn main() {
|
||||
println!("Hello, world!");
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue