diff --git a/solver-rs/.gitignore b/solver-rs/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/solver-rs/.gitignore @@ -0,0 +1 @@ +/target diff --git a/solver-rs/.vscode/launch.json b/solver-rs/.vscode/launch.json new file mode 100644 index 0000000..d9bde66 --- /dev/null +++ b/solver-rs/.vscode/launch.json @@ -0,0 +1,46 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "lldb", + "request": "launch", + "name": "Debug unit tests in library 'board'", + "cargo": { + "args": [ + "test", + "--no-run", + "--lib", + "--package=board" + ], + "filter": { + "name": "board", + "kind": "lib" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + }, + { + "type": "lldb", + "request": "launch", + "name": "Debug unit tests in library 'solver'", + "cargo": { + "args": [ + "test", + "--no-run", + "--lib", + "--package=solver" + ], + "filter": { + "name": "solver", + "kind": "lib" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + } + ] +} \ No newline at end of file diff --git a/solver-rs/.vscode/tasks.json b/solver-rs/.vscode/tasks.json new file mode 100644 index 0000000..ebe12ef --- /dev/null +++ b/solver-rs/.vscode/tasks.json @@ -0,0 +1,26 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "type": "cargo", + "subcommand": "build", + "problemMatcher": [ + "$rustc" + ], + "group": "build" + }, + { + "type": "cargo", + "subcommand": "check", + "problemMatcher": [ + "$rustc" + ], + "group": { + "kind": "build", + "isDefault": true + } + } + ] +} \ No newline at end of file diff --git a/solver-rs/Cargo.lock b/solver-rs/Cargo.lock new file mode 100644 index 0000000..8fb6246 --- /dev/null +++ b/solver-rs/Cargo.lock @@ -0,0 +1,375 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "action_optimization" +version = "0.1.0" +dependencies = [ + "actions", + "board", + "petgraph", + "serde", + "serde_json", +] + +[[package]] +name = "actions" +version = "0.1.0" +dependencies = [ + "board", + "enum-iterator", + "serde", + "serde_json", +] + +[[package]] +name = "ansi_term" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +dependencies = [ + "winapi", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + +[[package]] +name = "board" +version = "0.1.0" +dependencies = [ + "enum-iterator", + "serde", + "serde_json", +] + +[[package]] +name = "clap" +version = "2.33.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129" +dependencies = [ + "ansi_term", + "atty", + "bitflags", + "strsim", + "textwrap", + "unicode-width", + "vec_map", +] + +[[package]] +name = "enum-iterator" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c79a6321a1197d7730510c7e3f6cb80432dfefecb32426de8cea0aa19b4bb8d7" +dependencies = [ + "enum-iterator-derive", +] + +[[package]] +name = "enum-iterator-derive" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e94aa31f7c0dc764f57896dc615ddd76fc13b0d5dca7eb6cc5e018a5a09ec06" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "fixedbitset" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d" + +[[package]] +name = "heck" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "hermit-abi" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91780f809e750b0a89f5544be56617ff6b1227ee485bcb06ebe10cdf89bd3b71" +dependencies = [ + "libc", +] + +[[package]] +name = "indexmap" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "076f042c5b7b98f31d205f1249267e12a6518c1481e9dae9764af19b707d2292" +dependencies = [ + "autocfg", +] + +[[package]] +name = "itoa" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49" + +[[package]] +name = "petgraph" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7" +dependencies = [ + "fixedbitset", + "indexmap", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98e9e4b82e0ef281812565ea4751049f1bdcdfccda7d3f459f2e138a40c08678" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f5444ead4e9935abd7f27dc51f7e852a0569ac888096d5ec2499470794e2e53" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "syn-mid", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c09721c6781493a2a492a96b5a5bf19b65917fe6728884e7c44dd0c60ca3435" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "ryu" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "535622e6be132bccd223f4bb2b8ac8d53cda3c7a6394944d3b2b33fb974f9d76" + +[[package]] +name = "serde" +version = "1.0.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e707fbbf255b8fc8c3b99abb91e7257a622caeb20a9818cbadbeeede4e0932ff" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac5d00fc561ba2724df6758a17de23df5914f20e41cb00f94d5b7ae42fffaff8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78a7a12c167809363ec3bd7329fc0a3369056996de43c4b37ef3cd54a6ce4867" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "shenzhen" +version = "0.1.0" +dependencies = [ + "action_optimization", + "actions", + "board", + "serde", + "serde_json", + "solving", + "structopt", +] + +[[package]] +name = "solving" +version = "0.1.0" +dependencies = [ + "action_optimization", + "actions", + "board", +] + +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + +[[package]] +name = "structopt" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "863246aaf5ddd0d6928dfeb1a9ca65f505599e4e1b399935ef7e75107516b4ef" +dependencies = [ + "clap", + "lazy_static", + "structopt-derive", +] + +[[package]] +name = "structopt-derive" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d239ca4b13aee7a2142e6795cbd69e457665ff8037aed33b3effdc430d2f927a" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0df0eb663f387145cab623dea85b09c2c5b4b0aef44e945d928e682fce71bb03" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "syn-mid" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7be3539f6c128a931cf19dcee741c1af532c7fd387baa739c03dd2e96479338a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "unicode-segmentation" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0" + +[[package]] +name = "unicode-width" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" + +[[package]] +name = "unicode-xid" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" + +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + +[[package]] +name = "version_check" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" + +[[package]] +name = "winapi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" +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" diff --git a/solver-rs/Cargo.toml b/solver-rs/Cargo.toml new file mode 100644 index 0000000..c939388 --- /dev/null +++ b/solver-rs/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "shenzhen" +version = "0.1.0" +authors = ["Lukas Wölfer "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +board = {path = "lib/board"} +actions = {path = "lib/actions"} +action_optimization = {path = "lib/action_optimization"} +solving = {path = "lib/solving"} + +serde = {version="1.0.105",features=["derive"]} +serde_json = "1.0" +structopt = "0.3.14" \ No newline at end of file diff --git a/solver-rs/README.md b/solver-rs/README.md new file mode 100644 index 0000000..393fa4c --- /dev/null +++ b/solver-rs/README.md @@ -0,0 +1 @@ +# SHENZHEN I/O Solitaire Solver \ No newline at end of file diff --git a/solver-rs/aux/actions/01.json b/solver-rs/aux/actions/01.json new file mode 100644 index 0000000..7c0fc9b --- /dev/null +++ b/solver-rs/aux/actions/01.json @@ -0,0 +1 @@ +[{"Move":{"start_card":{"Number":{"value":5,"suit":"Red"}},"stack_len":2,"pattern":1,"source":{"column":3,"row":3},"destination":{"column":4,"row":5}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":4,"pattern":5,"source":{"column":4,"row":3},"destination":{"column":5,"row":5}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Black"}},"stack_len":5,"pattern":10,"source":{"column":5,"row":4},"destination":{"column":4,"row":3}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":7,"row":4},"destination":{"column":3,"row":3}}},{"Goal":{"card":{"value":1,"suit":"Red"},"source":{"Field":{"column":7,"row":3}},"goal_slot_index":0}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":0,"row":4},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":5,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":2,"row":4},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":3,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":2,"row":3},"destination":{"column":4,"row":8}}},{"Bunkerize":{"card":{"Number":{"value":5,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":2,"row":3},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Black"}},"stack_len":6,"pattern":10,"source":{"column":4,"row":3},"destination":{"column":6,"row":5}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":5,"pattern":5,"source":{"column":6,"row":6},"destination":{"column":3,"row":4}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":6,"row":5},"destination":{"column":4,"row":3}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Green"}},"stack_len":6,"pattern":11,"source":{"column":3,"row":3},"destination":{"column":6,"row":5}}},{"Move":{"start_card":{"Number":{"value":2,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":7,"row":2},"destination":{"column":6,"row":11}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Green"}},"stack_len":7,"pattern":43,"source":{"column":6,"row":5},"destination":{"column":3,"row":3}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":6,"pattern":21,"source":{"column":3,"row":4},"destination":{"column":4,"row":4}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Black"}},"stack_len":7,"pattern":42,"source":{"column":4,"row":3},"destination":{"column":6,"row":5}}},{"Bunkerize":{"card":{"Number":{"value":5,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":2,"row":3},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Green"}},"bunker_slot_index":2,"field_position":{"column":3,"row":3},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":5,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":2,"row":3},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":9,"suit":"Green"}},"bunker_slot_index":1,"field_position":{"column":4,"row":2},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Green"}},"bunker_slot_index":2,"field_position":{"column":3,"row":3},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":2,"field_position":{"column":4,"row":1},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Red"}},"stack_len":2,"pattern":1,"source":{"column":2,"row":2},"destination":{"column":4,"row":1}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Black"}},"stack_len":3,"pattern":2,"source":{"column":4,"row":0},"destination":{"column":3,"row":4}}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":4,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":0,"field_position":{"column":2,"row":1},"to_bunker":true}},{"DragonKill":{"card":"Zhong","source":[{"Bunker":{"slot_index":2}},{"Field":{"column":1,"row":4}},{"Field":{"column":2,"row":0}},{"Field":{"column":4,"row":0}}],"destination_slot_index":2}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":0,"field_position":{"column":2,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":9,"suit":"Green"}},"bunker_slot_index":1,"field_position":{"column":4,"row":0},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":4,"suit":"Black"}},"stack_len":3,"pattern":2,"source":{"column":6,"row":9},"destination":{"column":1,"row":4}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Black"}},"stack_len":4,"pattern":2,"source":{"column":6,"row":5},"destination":{"column":4,"row":1}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Green"}},"stack_len":4,"pattern":4,"source":{"column":3,"row":3},"destination":{"column":6,"row":5}}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":0,"row":3},"to_bunker":true}},{"Goal":{"card":{"value":1,"suit":"Green"},"source":{"Field":{"column":0,"row":2}},"goal_slot_index":1}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":1,"field_position":{"column":2,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":2,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":5,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":4,"row":4},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Green"}},"stack_len":4,"pattern":4,"source":{"column":1,"row":3},"destination":{"column":4,"row":4}}},{"Bunkerize":{"card":{"Number":{"value":5,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":1,"row":3},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":2,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":1,"field_position":{"column":2,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":5,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":6,"row":8},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Green"}},"stack_len":3,"pattern":0,"source":{"column":6,"row":5},"destination":{"column":3,"row":3}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Black"}},"stack_len":7,"pattern":38,"source":{"column":4,"row":1},"destination":{"column":6,"row":5}}},{"Bunkerize":{"card":{"Number":{"value":5,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":3,"row":6},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":1,"field_position":{"column":2,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":2,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":9,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":4,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":1,"field_position":{"column":4,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":1,"field_position":{"column":2,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Green"}},"stack_len":2,"pattern":1,"source":{"column":1,"row":2},"destination":{"column":2,"row":0}}},{"Goal":{"card":{"value":1,"suit":"Black"},"source":{"Field":{"column":1,"row":1}},"goal_slot_index":2}},{"Goal":{"card":{"value":2,"suit":"Green"},"source":{"Field":{"column":1,"row":0}},"goal_slot_index":1}},{"Goal":{"card":{"value":2,"suit":"Black"},"source":{"Field":{"column":6,"row":11}},"goal_slot_index":2}},{"Bunkerize":{"card":{"Number":{"value":9,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":1,"row":0},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Black"}},"stack_len":6,"pattern":6,"source":{"column":6,"row":5},"destination":{"column":1,"row":1}}},{"Move":{"start_card":{"Number":{"value":4,"suit":"Black"}},"stack_len":2,"pattern":0,"source":{"column":1,"row":5},"destination":{"column":2,"row":2}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Black"}},"stack_len":4,"pattern":6,"source":{"column":1,"row":1},"destination":{"column":6,"row":5}}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":0,"row":1},"to_bunker":true}},{"Goal":{"card":{"value":3,"suit":"Green"},"source":{"Field":{"column":0,"row":0}},"goal_slot_index":1}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":9,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":1,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":1,"field_position":{"column":1,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":5,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":3,"row":6},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":6,"row":8},"destination":{"column":3,"row":6}}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Red"}},"stack_len":3,"pattern":1,"source":{"column":2,"row":1},"destination":{"column":6,"row":8}}},{"Bunkerize":{"card":{"Number":{"value":5,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":2,"row":1},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":9,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":1,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Red"}},"stack_len":2,"pattern":0,"source":{"column":3,"row":5},"destination":{"column":1,"row":0}}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Green"}},"stack_len":2,"pattern":0,"source":{"column":2,"row":0},"destination":{"column":3,"row":5}}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":2,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":9,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":1,"field_position":{"column":4,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":9,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":4,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Special":"Bai"},"stack_len":1,"pattern":0,"source":{"column":5,"row":3},"destination":{"column":0,"row":0}}},{"Goal":{"card":{"value":3,"suit":"Black"},"source":{"Field":{"column":5,"row":2}},"goal_slot_index":2}},{"DragonKill":{"card":"Bai","source":[{"Bunker":{"slot_index":1}},{"Field":{"column":0,"row":0}},{"Field":{"column":5,"row":1}},{"Field":{"column":7,"row":1}}],"destination_slot_index":1}},{"Goal":{"card":{"value":2,"suit":"Red"},"source":{"Field":{"column":5,"row":0}},"goal_slot_index":0}},{"Goal":{"card":{"value":3,"suit":"Red"},"source":{"Field":{"column":6,"row":10}},"goal_slot_index":0}},{"Goal":{"card":{"value":4,"suit":"Black"},"source":{"Field":{"column":6,"row":9}},"goal_slot_index":2}},{"Goal":{"card":{"value":5,"suit":"Black"},"source":{"Field":{"column":3,"row":6}},"goal_slot_index":2}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":9,"suit":"Black"}},"stack_len":4,"pattern":5,"source":{"column":3,"row":2},"destination":{"column":5,"row":0}}},{"Goal":{"card":{"value":4,"suit":"Red"},"source":{"Field":{"column":3,"row":1}},"goal_slot_index":0}},{"Goal":{"card":{"value":5,"suit":"Red"},"source":{"Field":{"column":6,"row":8}},"goal_slot_index":0}},{"Goal":{"card":{"value":6,"suit":"Black"},"source":{"Field":{"column":6,"row":7}},"goal_slot_index":2}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Black"}},"stack_len":2,"pattern":1,"source":{"column":5,"row":2},"destination":{"column":7,"row":1}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Black"}},"stack_len":2,"pattern":0,"source":{"column":6,"row":5},"destination":{"column":4,"row":1}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":4,"row":2},"destination":{"column":5,"row":2}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Green"}},"stack_len":2,"pattern":1,"source":{"column":5,"row":1},"destination":{"column":6,"row":5}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Red"}},"stack_len":3,"pattern":3,"source":{"column":7,"row":0},"destination":{"column":5,"row":1}}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":5,"row":3},"destination":{"column":6,"row":7}}},{"Goal":{"card":{"value":7,"suit":"Black"},"source":{"Field":{"column":5,"row":2}},"goal_slot_index":2}},{"Goal":{"card":{"value":8,"suit":"Black"},"source":{"Field":{"column":4,"row":1}},"goal_slot_index":2}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":5,"row":1},"destination":{"column":4,"row":1}}},{"Goal":{"card":{"value":9,"suit":"Black"},"source":{"Field":{"column":5,"row":0}},"goal_slot_index":2}},{"Move":{"start_card":{"Number":{"value":9,"suit":"Red"}},"stack_len":4,"pattern":2,"source":{"column":6,"row":4},"destination":{"column":5,"row":0}}},{"DragonKill":{"card":"Fa","source":[{"Field":{"column":0,"row":0}},{"Field":{"column":2,"row":0}},{"Field":{"column":3,"row":0}},{"Field":{"column":6,"row":3}}],"destination_slot_index":0}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Green"}},"stack_len":3,"pattern":1,"source":{"column":5,"row":1},"destination":{"column":0,"row":0}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":2,"pattern":0,"source":{"column":0,"row":1},"destination":{"column":2,"row":0}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":6,"row":2},"destination":{"column":4,"row":2}}},{"HuaKill":{"field_position":{"column":6,"row":1}}},{"Goal":{"card":{"value":4,"suit":"Green"},"source":{"Field":{"column":6,"row":0}},"goal_slot_index":1}},{"Goal":{"card":{"value":5,"suit":"Green"},"source":{"Field":{"column":1,"row":1}},"goal_slot_index":1}},{"Goal":{"card":{"value":6,"suit":"Red"},"source":{"Field":{"column":1,"row":0}},"goal_slot_index":0}},{"Goal":{"card":{"value":6,"suit":"Green"},"source":{"Field":{"column":2,"row":1}},"goal_slot_index":1}},{"Goal":{"card":{"value":7,"suit":"Red"},"source":{"Field":{"column":2,"row":0}},"goal_slot_index":0}},{"Goal":{"card":{"value":7,"suit":"Green"},"source":{"Field":{"column":4,"row":2}},"goal_slot_index":1}},{"Goal":{"card":{"value":8,"suit":"Green"},"source":{"Field":{"column":0,"row":0}},"goal_slot_index":1}},{"Goal":{"card":{"value":8,"suit":"Red"},"source":{"Field":{"column":4,"row":1}},"goal_slot_index":0}},{"Goal":{"card":{"value":9,"suit":"Green"},"source":{"Field":{"column":4,"row":0}},"goal_slot_index":1}},{"Goal":{"card":{"value":9,"suit":"Red"},"source":{"Field":{"column":5,"row":0}},"goal_slot_index":0}}] \ No newline at end of file diff --git a/solver-rs/aux/actions/02.json b/solver-rs/aux/actions/02.json new file mode 100644 index 0000000..9190cb1 --- /dev/null +++ b/solver-rs/aux/actions/02.json @@ -0,0 +1 @@ +[{"Move":{"start_card":{"Number":{"value":2,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":1,"row":4},"destination":{"column":6,"row":5}}},{"DragonKill":{"card":"Zhong","source":[{"Field":{"column":1,"row":3}},{"Field":{"column":3,"row":4}},{"Field":{"column":5,"row":4}},{"Field":{"column":7,"row":4}}],"destination_slot_index":0}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":3,"row":3},"destination":{"column":0,"row":5}}},{"Move":{"start_card":{"Number":{"value":4,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":2,"row":4},"destination":{"column":3,"row":3}}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":2,"row":3},"destination":{"column":0,"row":6}}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Black"}},"stack_len":2,"pattern":1,"source":{"column":3,"row":2},"destination":{"column":0,"row":7}}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Green"}},"stack_len":3,"pattern":2,"source":{"column":0,"row":6},"destination":{"column":3,"row":2}}},{"Move":{"start_card":{"Number":{"value":2,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":4,"row":4},"destination":{"column":5,"row":4}}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":2,"row":2},"destination":{"column":4,"row":4}}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Black"}},"stack_len":2,"pattern":1,"source":{"column":4,"row":3},"destination":{"column":0,"row":6}}},{"Move":{"start_card":{"Number":{"value":3,"suit":"Black"}},"stack_len":2,"pattern":0,"source":{"column":5,"row":3},"destination":{"column":3,"row":5}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":3,"pattern":3,"source":{"column":0,"row":5},"destination":{"column":5,"row":3}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Black"}},"stack_len":6,"pattern":5,"source":{"column":3,"row":1},"destination":{"column":0,"row":5}}},{"Goal":{"card":{"value":1,"suit":"Black"},"source":{"Field":{"column":3,"row":0}},"goal_slot_index":0}},{"Goal":{"card":{"value":2,"suit":"Black"},"source":{"Field":{"column":7,"row":3}},"goal_slot_index":0}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Green"}},"stack_len":7,"pattern":10,"source":{"column":0,"row":4},"destination":{"column":3,"row":0}}},{"HuaKill":{"field_position":{"column":0,"row":3}}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":2,"row":1},"destination":{"column":7,"row":3}}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Black"}},"stack_len":4,"pattern":1,"source":{"column":3,"row":3},"destination":{"column":7,"row":4}}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Green"}},"bunker_slot_index":1,"field_position":{"column":0,"row":2},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":2,"field_position":{"column":0,"row":1},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Green"}},"stack_len":6,"pattern":7,"source":{"column":7,"row":2},"destination":{"column":0,"row":1}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Red"}},"stack_len":7,"pattern":14,"source":{"column":0,"row":0},"destination":{"column":7,"row":2}}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Green"}},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":1,"field_position":{"column":1,"row":2},"to_bunker":true}},{"Goal":{"card":{"value":1,"suit":"Green"},"source":{"Field":{"column":1,"row":1}},"goal_slot_index":1}},{"Goal":{"card":{"value":2,"suit":"Green"},"source":{"Field":{"column":6,"row":5}},"goal_slot_index":1}},{"Goal":{"card":{"value":3,"suit":"Green"},"source":{"Field":{"column":0,"row":0}},"goal_slot_index":1}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":1,"field_position":{"column":2,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Special":"Fa"},"stack_len":1,"pattern":0,"source":{"column":4,"row":2},"destination":{"column":2,"row":0}}},{"Goal":{"card":{"value":1,"suit":"Red"},"source":{"Field":{"column":4,"row":1}},"goal_slot_index":2}},{"Goal":{"card":{"value":2,"suit":"Red"},"source":{"Field":{"column":7,"row":8}},"goal_slot_index":2}},{"Goal":{"card":{"value":3,"suit":"Red"},"source":{"Field":{"column":6,"row":4}},"goal_slot_index":2}},{"Goal":{"card":{"value":3,"suit":"Black"},"source":{"Field":{"column":7,"row":7}},"goal_slot_index":0}},{"Goal":{"card":{"value":4,"suit":"Green"},"source":{"Field":{"column":7,"row":6}},"goal_slot_index":1}},{"Goal":{"card":{"value":5,"suit":"Green"},"source":{"Field":{"column":5,"row":5}},"goal_slot_index":1}},{"Goal":{"card":{"value":6,"suit":"Green"},"source":{"Field":{"column":3,"row":2}},"goal_slot_index":1}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Red"}},"stack_len":2,"pattern":1,"source":{"column":7,"row":4},"destination":{"column":3,"row":2}}},{"Goal":{"card":{"value":7,"suit":"Green"},"source":{"Field":{"column":7,"row":3}},"goal_slot_index":1}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Black"}},"stack_len":3,"pattern":2,"source":{"column":3,"row":1},"destination":{"column":7,"row":3}}},{"Goal":{"card":{"value":8,"suit":"Green"},"source":{"Field":{"column":3,"row":0}},"goal_slot_index":1}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":1,"field_position":{"column":3,"row":0},"to_bunker":false}},{"DragonKill":{"card":"Bai","source":[{"Field":{"column":0,"row":0}},{"Field":{"column":1,"row":0}},{"Field":{"column":4,"row":0}},{"Field":{"column":6,"row":3}}],"destination_slot_index":1}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":2,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Black"}},"stack_len":3,"pattern":2,"source":{"column":5,"row":2},"destination":{"column":6,"row":3}}},{"DragonKill":{"card":"Fa","source":[{"Field":{"column":0,"row":0}},{"Field":{"column":2,"row":0}},{"Field":{"column":3,"row":0}},{"Field":{"column":5,"row":1}}],"destination_slot_index":2}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":5,"row":0},"destination":{"column":6,"row":6}}},{"Move":{"start_card":{"Number":{"value":9,"suit":"Red"}},"stack_len":5,"pattern":5,"source":{"column":6,"row":2},"destination":{"column":0,"row":0}}},{"Goal":{"card":{"value":4,"suit":"Black"},"source":{"Field":{"column":6,"row":1}},"goal_slot_index":0}},{"Goal":{"card":{"value":4,"suit":"Red"},"source":{"Field":{"column":6,"row":0}},"goal_slot_index":2}},{"Goal":{"card":{"value":5,"suit":"Red"},"source":{"Field":{"column":0,"row":4}},"goal_slot_index":2}},{"Goal":{"card":{"value":5,"suit":"Black"},"source":{"Field":{"column":7,"row":5}},"goal_slot_index":0}},{"Goal":{"card":{"value":6,"suit":"Black"},"source":{"Field":{"column":0,"row":3}},"goal_slot_index":0}},{"Goal":{"card":{"value":6,"suit":"Red"},"source":{"Field":{"column":7,"row":4}},"goal_slot_index":2}},{"Goal":{"card":{"value":7,"suit":"Red"},"source":{"Field":{"column":0,"row":2}},"goal_slot_index":2}},{"Goal":{"card":{"value":7,"suit":"Black"},"source":{"Field":{"column":7,"row":3}},"goal_slot_index":0}},{"Goal":{"card":{"value":8,"suit":"Black"},"source":{"Field":{"column":0,"row":1}},"goal_slot_index":0}},{"Goal":{"card":{"value":8,"suit":"Red"},"source":{"Field":{"column":7,"row":2}},"goal_slot_index":2}},{"Goal":{"card":{"value":9,"suit":"Red"},"source":{"Field":{"column":0,"row":0}},"goal_slot_index":2}},{"Goal":{"card":{"value":9,"suit":"Green"},"source":{"Field":{"column":7,"row":1}},"goal_slot_index":1}},{"Goal":{"card":{"value":9,"suit":"Black"},"source":{"Field":{"column":7,"row":0}},"goal_slot_index":0}}] \ No newline at end of file diff --git a/solver-rs/aux/actions/03.json b/solver-rs/aux/actions/03.json new file mode 100644 index 0000000..c0217cb --- /dev/null +++ b/solver-rs/aux/actions/03.json @@ -0,0 +1 @@ +[{"Move":{"start_card":{"Number":{"value":7,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":6,"row":4},"destination":{"column":0,"row":5}}},{"Bunkerize":{"card":{"Number":{"value":7,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":0,"row":5},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":7,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":0,"row":5},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":3,"row":4},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":7,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":0,"row":5},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":2,"field_position":{"column":6,"row":3},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":7,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":0,"row":5},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":6,"row":2},"to_bunker":true}},{"DragonKill":{"card":"Zhong","source":[{"Bunker":{"slot_index":0}},{"Field":{"column":2,"row":4}},{"Field":{"column":3,"row":3}},{"Field":{"column":6,"row":1}}],"destination_slot_index":0}},{"Move":{"start_card":{"Number":{"value":2,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":1,"row":4},"destination":{"column":6,"row":1}}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":2,"row":3},"destination":{"column":1,"row":4}}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":3,"row":2},"destination":{"column":1,"row":5}}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":3,"row":2},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":3,"suit":"Black"}},"stack_len":2,"pattern":0,"source":{"column":6,"row":0},"destination":{"column":3,"row":3}}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":2,"field_position":{"column":6,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":7,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":0,"row":5},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":3,"pattern":1,"source":{"column":1,"row":3},"destination":{"column":0,"row":5}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Green"}},"stack_len":4,"pattern":3,"source":{"column":0,"row":4},"destination":{"column":1,"row":3}}},{"Move":{"start_card":{"Number":{"value":4,"suit":"Red"}},"stack_len":3,"pattern":1,"source":{"column":3,"row":2},"destination":{"column":0,"row":4}}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":2,"field_position":{"column":2,"row":2},"to_bunker":true}},{"Goal":{"card":{"value":1,"suit":"Black"},"source":{"Field":{"column":2,"row":1}},"goal_slot_index":0}},{"Goal":{"card":{"value":1,"suit":"Green"},"source":{"Field":{"column":2,"row":0}},"goal_slot_index":1}},{"Goal":{"card":{"value":2,"suit":"Green"},"source":{"Field":{"column":4,"row":4}},"goal_slot_index":1}},{"Bunkerize":{"card":{"Number":{"value":7,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":2,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":1,"field_position":{"column":6,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":2,"field_position":{"column":6,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":7,"suit":"Black"}},"bunker_slot_index":2,"field_position":{"column":2,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":9,"suit":"Red"}},"stack_len":5,"pattern":6,"source":{"column":1,"row":2},"destination":{"column":2,"row":0}}},{"Goal":{"card":{"value":3,"suit":"Green"},"source":{"Field":{"column":1,"row":1}},"goal_slot_index":1}},{"Goal":{"card":{"value":2,"suit":"Black"},"source":{"Field":{"column":1,"row":0}},"goal_slot_index":0}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":1,"field_position":{"column":1,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":1,"field_position":{"column":6,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":7,"suit":"Black"}},"bunker_slot_index":2,"field_position":{"column":6,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":2,"field_position":{"column":1,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":1,"field_position":{"column":1,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":1,"field_position":{"column":7,"row":4},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Black"}},"stack_len":4,"pattern":2,"source":{"column":0,"row":3},"destination":{"column":7,"row":4}}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Red"}},"stack_len":5,"pattern":5,"source":{"column":7,"row":3},"destination":{"column":6,"row":1}}},{"Move":{"start_card":{"Number":{"value":4,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":7,"row":2},"destination":{"column":2,"row":5}}},{"DragonKill":{"card":"Bai","source":[{"Bunker":{"slot_index":1}},{"Bunker":{"slot_index":2}},{"Field":{"column":4,"row":3}},{"Field":{"column":7,"row":1}}],"destination_slot_index":1}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Black"}},"stack_len":3,"pattern":2,"source":{"column":2,"row":3},"destination":{"column":7,"row":1}}},{"Move":{"start_card":{"Number":{"value":3,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":4,"row":2},"destination":{"column":7,"row":4}}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":4,"row":1},"destination":{"column":2,"row":3}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Black"}},"stack_len":6,"pattern":10,"source":{"column":6,"row":0},"destination":{"column":4,"row":1}}},{"Move":{"start_card":{"Special":"Fa"},"stack_len":1,"pattern":0,"source":{"column":0,"row":2},"destination":{"column":6,"row":0}}},{"Goal":{"card":{"value":1,"suit":"Red"},"source":{"Field":{"column":0,"row":1}},"goal_slot_index":2}},{"Goal":{"card":{"value":2,"suit":"Red"},"source":{"Field":{"column":4,"row":6}},"goal_slot_index":2}},{"Goal":{"card":{"value":3,"suit":"Black"},"source":{"Field":{"column":4,"row":5}},"goal_slot_index":0}},{"Goal":{"card":{"value":3,"suit":"Red"},"source":{"Field":{"column":7,"row":4}},"goal_slot_index":2}},{"Goal":{"card":{"value":4,"suit":"Green"},"source":{"Field":{"column":0,"row":0}},"goal_slot_index":1}},{"Goal":{"card":{"value":4,"suit":"Red"},"source":{"Field":{"column":4,"row":4}},"goal_slot_index":2}},{"Goal":{"card":{"value":4,"suit":"Black"},"source":{"Field":{"column":7,"row":3}},"goal_slot_index":0}},{"Goal":{"card":{"value":5,"suit":"Green"},"source":{"Field":{"column":3,"row":1}},"goal_slot_index":1}},{"Goal":{"card":{"value":5,"suit":"Black"},"source":{"Field":{"column":4,"row":3}},"goal_slot_index":0}},{"Goal":{"card":{"value":5,"suit":"Red"},"source":{"Field":{"column":7,"row":2}},"goal_slot_index":2}},{"Goal":{"card":{"value":6,"suit":"Green"},"source":{"Field":{"column":2,"row":3}},"goal_slot_index":1}},{"Goal":{"card":{"value":6,"suit":"Red"},"source":{"Field":{"column":4,"row":2}},"goal_slot_index":2}},{"Goal":{"card":{"value":6,"suit":"Black"},"source":{"Field":{"column":7,"row":1}},"goal_slot_index":0}},{"Goal":{"card":{"value":7,"suit":"Red"},"source":{"Field":{"column":2,"row":2}},"goal_slot_index":2}},{"Goal":{"card":{"value":7,"suit":"Black"},"source":{"Field":{"column":4,"row":1}},"goal_slot_index":0}},{"Goal":{"card":{"value":7,"suit":"Green"},"source":{"Field":{"column":7,"row":0}},"goal_slot_index":1}},{"Goal":{"card":{"value":8,"suit":"Green"},"source":{"Field":{"column":2,"row":1}},"goal_slot_index":1}},{"Goal":{"card":{"value":8,"suit":"Red"},"source":{"Field":{"column":4,"row":0}},"goal_slot_index":2}},{"DragonKill":{"card":"Fa","source":[{"Field":{"column":1,"row":0}},{"Field":{"column":3,"row":0}},{"Field":{"column":5,"row":4}},{"Field":{"column":6,"row":0}}],"destination_slot_index":2}},{"Goal":{"card":{"value":8,"suit":"Black"},"source":{"Field":{"column":5,"row":3}},"goal_slot_index":0}},{"Goal":{"card":{"value":9,"suit":"Red"},"source":{"Field":{"column":2,"row":0}},"goal_slot_index":2}},{"Goal":{"card":{"value":9,"suit":"Black"},"source":{"Field":{"column":5,"row":2}},"goal_slot_index":0}},{"HuaKill":{"field_position":{"column":5,"row":1}}},{"Goal":{"card":{"value":9,"suit":"Green"},"source":{"Field":{"column":5,"row":0}},"goal_slot_index":1}}] \ No newline at end of file diff --git a/solver-rs/aux/actions/04.json b/solver-rs/aux/actions/04.json new file mode 100644 index 0000000..f0c8d41 --- /dev/null +++ b/solver-rs/aux/actions/04.json @@ -0,0 +1 @@ +[{"Move":{"start_card":{"Number":{"value":4,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":3,"row":4},"destination":{"column":4,"row":5}}},{"Move":{"start_card":{"Number":{"value":3,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":7,"row":4},"destination":{"column":1,"row":3}}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":0,"field_position":{"column":0,"row":4},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":0,"row":3},"destination":{"column":7,"row":4}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":0,"row":2},"destination":{"column":6,"row":5}}},{"Move":{"start_card":{"Number":{"value":4,"suit":"Black"}},"stack_len":2,"pattern":0,"source":{"column":1,"row":2},"destination":{"column":0,"row":2}}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":0,"row":3},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Black"}},"bunker_slot_index":2,"field_position":{"column":0,"row":2},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":4,"row":6},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":1,"field_position":{"column":1,"row":1},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Black"}},"bunker_slot_index":2,"field_position":{"column":0,"row":2},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Green"}},"stack_len":2,"pattern":1,"source":{"column":6,"row":4},"destination":{"column":1,"row":1}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Black"}},"stack_len":2,"pattern":1,"source":{"column":7,"row":3},"destination":{"column":6,"row":4}}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":2,"field_position":{"column":5,"row":4},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Black"}},"stack_len":3,"pattern":3,"source":{"column":4,"row":4},"destination":{"column":5,"row":4}}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Green"}},"stack_len":4,"pattern":6,"source":{"column":5,"row":3},"destination":{"column":1,"row":3}}},{"Goal":{"card":{"value":2,"suit":"Red"},"source":{"Field":{"column":5,"row":2}},"goal_slot_index":0}},{"Move":{"start_card":{"Number":{"value":2,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":5,"row":1},"destination":{"column":1,"row":7}}},{"Move":{"start_card":{"Number":{"value":3,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":5,"row":0},"destination":{"column":0,"row":3}}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":0,"field_position":{"column":5,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":7,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":6,"row":5},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":6,"pattern":12,"source":{"column":1,"row":2},"destination":{"column":6,"row":5}}},{"Bunkerize":{"card":{"Number":{"value":7,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":7,"row":3},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":0,"field_position":{"column":5,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":9,"suit":"Green"}},"stack_len":8,"pattern":48,"source":{"column":6,"row":3},"destination":{"column":5,"row":0}}},{"Goal":{"card":{"value":2,"suit":"Black"},"source":{"Field":{"column":6,"row":2}},"goal_slot_index":1}},{"Move":{"start_card":{"Number":{"value":4,"suit":"Black"}},"stack_len":2,"pattern":1,"source":{"column":0,"row":2},"destination":{"column":6,"row":2}}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Black"}},"stack_len":4,"pattern":6,"source":{"column":6,"row":0},"destination":{"column":7,"row":4}}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":0,"field_position":{"column":6,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":2,"row":4},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":4,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":2,"row":3},"destination":{"column":0,"row":2}}},{"Goal":{"card":{"value":1,"suit":"Green"},"source":{"Field":{"column":2,"row":2}},"goal_slot_index":2}},{"Goal":{"card":{"value":2,"suit":"Green"},"source":{"Field":{"column":5,"row":7}},"goal_slot_index":2}},{"Goal":{"card":{"value":3,"suit":"Red"},"source":{"Field":{"column":5,"row":6}},"goal_slot_index":0}},{"Goal":{"card":{"value":3,"suit":"Green"},"source":{"Field":{"column":7,"row":7}},"goal_slot_index":2}},{"Goal":{"card":{"value":4,"suit":"Red"},"source":{"Field":{"column":0,"row":2}},"goal_slot_index":0}},{"Goal":{"card":{"value":4,"suit":"Green"},"source":{"Field":{"column":5,"row":5}},"goal_slot_index":2}},{"Goal":{"card":{"value":5,"suit":"Green"},"source":{"Field":{"column":0,"row":1}},"goal_slot_index":2}},{"DragonKill":{"card":"Bai","source":[{"Bunker":{"slot_index":1}},{"Field":{"column":0,"row":0}},{"Field":{"column":2,"row":1}},{"Field":{"column":6,"row":0}}],"destination_slot_index":1}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":2,"field_position":{"column":6,"row":0},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":2,"row":0},"destination":{"column":1,"row":2}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Green"}},"stack_len":2,"pattern":0,"source":{"column":1,"row":1},"destination":{"column":2,"row":0}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Black"}},"stack_len":4,"pattern":0,"source":{"column":5,"row":1},"destination":{"column":1,"row":1}}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Green"}},"stack_len":2,"pattern":0,"source":{"column":1,"row":3},"destination":{"column":2,"row":2}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Black"}},"stack_len":2,"pattern":0,"source":{"column":1,"row":1},"destination":{"column":5,"row":1}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Green"}},"stack_len":4,"pattern":2,"source":{"column":2,"row":0},"destination":{"column":1,"row":1}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Black"}},"stack_len":3,"pattern":1,"source":{"column":1,"row":2},"destination":{"column":2,"row":0}}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Black"}},"stack_len":3,"pattern":2,"source":{"column":7,"row":4},"destination":{"column":5,"row":3}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":4,"pattern":5,"source":{"column":5,"row":2},"destination":{"column":1,"row":2}}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Green"}},"stack_len":5,"pattern":11,"source":{"column":1,"row":1},"destination":{"column":0,"row":0}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":5,"row":1},"destination":{"column":1,"row":1}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Red"}},"stack_len":2,"pattern":0,"source":{"column":7,"row":2},"destination":{"column":5,"row":1}}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Black"}},"bunker_slot_index":2,"field_position":{"column":0,"row":4},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":3,"pattern":1,"source":{"column":0,"row":1},"destination":{"column":1,"row":2}}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Black"}},"stack_len":2,"pattern":0,"source":{"column":1,"row":3},"destination":{"column":5,"row":3}}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Black"}},"bunker_slot_index":2,"field_position":{"column":5,"row":5},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Green"}},"bunker_slot_index":2,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":7,"row":1},"to_bunker":true}},{"HuaKill":{"field_position":{"column":7,"row":0}}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":7,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Green"}},"bunker_slot_index":2,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":7,"suit":"Red"}},"bunker_slot_index":2,"field_position":{"column":1,"row":2},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Green"}},"stack_len":4,"pattern":4,"source":{"column":5,"row":2},"destination":{"column":1,"row":2}}},{"Bunkerize":{"card":{"Number":{"value":7,"suit":"Red"}},"bunker_slot_index":2,"field_position":{"column":0,"row":1},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":5,"suit":"Black"}},"bunker_slot_index":2,"field_position":{"column":2,"row":2},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Red"}},"stack_len":2,"pattern":1,"source":{"column":1,"row":4},"destination":{"column":2,"row":2}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Green"}},"stack_len":2,"pattern":0,"source":{"column":1,"row":2},"destination":{"column":5,"row":2}}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":5,"row":3},"destination":{"column":0,"row":2}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":2,"pattern":1,"source":{"column":0,"row":1},"destination":{"column":1,"row":2}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Black"}},"stack_len":4,"pattern":7,"source":{"column":2,"row":0},"destination":{"column":0,"row":1}}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":2,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":0,"row":4},"to_bunker":true}},{"Goal":{"card":{"value":5,"suit":"Red"},"source":{"Field":{"column":0,"row":3}},"goal_slot_index":0}},{"Bunkerize":{"card":{"Number":{"value":5,"suit":"Black"}},"bunker_slot_index":2,"field_position":{"column":0,"row":3},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":2,"field_position":{"column":7,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":7,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":2,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":2,"field_position":{"column":2,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":2,"field_position":{"column":3,"row":3},"to_bunker":true}},{"DragonKill":{"card":"Zhong","source":[{"Bunker":{"slot_index":0}},{"Field":{"column":3,"row":2}},{"Field":{"column":4,"row":3}},{"Field":{"column":6,"row":0}}],"destination_slot_index":0}},{"Goal":{"card":{"value":6,"suit":"Red"},"source":{"Field":{"column":3,"row":1}},"goal_slot_index":0}},{"DragonKill":{"card":"Fa","source":[{"Bunker":{"slot_index":2}},{"Field":{"column":2,"row":0}},{"Field":{"column":3,"row":0}},{"Field":{"column":4,"row":2}}],"destination_slot_index":2}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":0,"row":3},"destination":{"column":2,"row":0}}},{"Goal":{"card":{"value":6,"suit":"Green"},"source":{"Field":{"column":0,"row":2}},"goal_slot_index":2}},{"Goal":{"card":{"value":7,"suit":"Green"},"source":{"Field":{"column":5,"row":2}},"goal_slot_index":2}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Black"}},"stack_len":3,"pattern":2,"source":{"column":1,"row":1},"destination":{"column":3,"row":0}}},{"Move":{"start_card":{"Number":{"value":9,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":4,"row":1},"destination":{"column":6,"row":0}}},{"Goal":{"card":{"value":3,"suit":"Black"},"source":{"Field":{"column":4,"row":0}},"goal_slot_index":1}},{"Goal":{"card":{"value":4,"suit":"Black"},"source":{"Field":{"column":7,"row":0}},"goal_slot_index":1}},{"Goal":{"card":{"value":5,"suit":"Black"},"source":{"Field":{"column":2,"row":0}},"goal_slot_index":1}},{"Goal":{"card":{"value":6,"suit":"Black"},"source":{"Field":{"column":3,"row":2}},"goal_slot_index":1}},{"Goal":{"card":{"value":7,"suit":"Black"},"source":{"Field":{"column":0,"row":1}},"goal_slot_index":1}},{"Goal":{"card":{"value":7,"suit":"Red"},"source":{"Field":{"column":3,"row":1}},"goal_slot_index":0}},{"Goal":{"card":{"value":8,"suit":"Green"},"source":{"Field":{"column":0,"row":0}},"goal_slot_index":2}},{"Goal":{"card":{"value":8,"suit":"Black"},"source":{"Field":{"column":3,"row":0}},"goal_slot_index":1}},{"Goal":{"card":{"value":8,"suit":"Red"},"source":{"Field":{"column":5,"row":1}},"goal_slot_index":0}},{"Goal":{"card":{"value":9,"suit":"Red"},"source":{"Field":{"column":1,"row":0}},"goal_slot_index":0}},{"Goal":{"card":{"value":9,"suit":"Green"},"source":{"Field":{"column":5,"row":0}},"goal_slot_index":2}},{"Goal":{"card":{"value":9,"suit":"Black"},"source":{"Field":{"column":6,"row":0}},"goal_slot_index":1}}] \ No newline at end of file diff --git a/solver-rs/aux/actions/05.json b/solver-rs/aux/actions/05.json new file mode 100644 index 0000000..157768b --- /dev/null +++ b/solver-rs/aux/actions/05.json @@ -0,0 +1 @@ +[{"Move":{"start_card":{"Number":{"value":4,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":0,"row":4},"destination":{"column":7,"row":5}}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":0,"field_position":{"column":0,"row":3},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":0,"row":2},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":1,"row":3},"destination":{"column":0,"row":2}}},{"Bunkerize":{"card":{"Number":{"value":7,"suit":"Red"}},"bunker_slot_index":2,"field_position":{"column":1,"row":2},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Red"}},"stack_len":2,"pattern":0,"source":{"column":7,"row":4},"destination":{"column":1,"row":2}}},{"Move":{"start_card":{"Number":{"value":2,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":3,"row":4},"destination":{"column":7,"row":4}}},{"Bunkerize":{"card":{"Number":{"value":7,"suit":"Red"}},"bunker_slot_index":2,"field_position":{"column":3,"row":4},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Black"}},"stack_len":3,"pattern":0,"source":{"column":1,"row":1},"destination":{"column":3,"row":5}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Red"}},"stack_len":2,"pattern":1,"source":{"column":0,"row":1},"destination":{"column":1,"row":1}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Black"}},"stack_len":5,"pattern":2,"source":{"column":3,"row":3},"destination":{"column":5,"row":5}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":4,"pattern":1,"source":{"column":5,"row":6},"destination":{"column":3,"row":3}}},{"Move":{"start_card":{"Number":{"value":3,"suit":"Black"}},"stack_len":2,"pattern":1,"source":{"column":7,"row":3},"destination":{"column":3,"row":7}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":6,"pattern":17,"source":{"column":3,"row":3},"destination":{"column":5,"row":6}}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":2,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":3,"row":2},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Black"}},"stack_len":7,"pattern":34,"source":{"column":5,"row":5},"destination":{"column":3,"row":2}}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":5,"row":5},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Green"}},"bunker_slot_index":1,"field_position":{"column":3,"row":8},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":5,"pattern":1,"source":{"column":3,"row":3},"destination":{"column":5,"row":6}}},{"Move":{"start_card":{"Number":{"value":3,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":5,"row":10},"destination":{"column":6,"row":5}}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Green"}},"bunker_slot_index":1,"field_position":{"column":6,"row":6},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":2,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":2,"field_position":{"column":4,"row":4},"to_bunker":true}},{"Goal":{"card":{"value":2,"suit":"Black"},"source":{"Field":{"column":4,"row":3}},"goal_slot_index":0}},{"Goal":{"card":{"value":1,"suit":"Green"},"source":{"Field":{"column":4,"row":2}},"goal_slot_index":1}},{"Goal":{"card":{"value":2,"suit":"Green"},"source":{"Field":{"column":6,"row":6}},"goal_slot_index":1}},{"Goal":{"card":{"value":3,"suit":"Black"},"source":{"Field":{"column":6,"row":5}},"goal_slot_index":0}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":4,"row":1},"destination":{"column":1,"row":3}}},{"DragonKill":{"card":"Bai","source":[{"Bunker":{"slot_index":0}},{"Field":{"column":2,"row":3}},{"Field":{"column":4,"row":0}},{"Field":{"column":7,"row":2}}],"destination_slot_index":0}},{"Goal":{"card":{"value":1,"suit":"Red"},"source":{"Field":{"column":7,"row":1}},"goal_slot_index":2}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":4,"row":0},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Black"}},"stack_len":2,"pattern":0,"source":{"column":6,"row":3},"destination":{"column":1,"row":4}}},{"Move":{"start_card":{"Number":{"value":4,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":1,"row":5},"destination":{"column":6,"row":3}}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":9,"suit":"Green"}},"stack_len":2,"pattern":0,"source":{"column":3,"row":1},"destination":{"column":0,"row":0}}},{"Move":{"start_card":{"Number":{"value":3,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":3,"row":0},"destination":{"column":5,"row":10}}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":1,"field_position":{"column":3,"row":0},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":5,"pattern":9,"source":{"column":5,"row":6},"destination":{"column":0,"row":2}}},{"Bunkerize":{"card":{"Number":{"value":5,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":1,"row":4},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Red"}},"stack_len":3,"pattern":2,"source":{"column":0,"row":4},"destination":{"column":1,"row":4}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":2,"pattern":1,"source":{"column":0,"row":2},"destination":{"column":5,"row":6}}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Green"}},"stack_len":2,"pattern":1,"source":{"column":6,"row":2},"destination":{"column":5,"row":8}}},{"Goal":{"card":{"value":4,"suit":"Black"},"source":{"Field":{"column":6,"row":1}},"goal_slot_index":0}},{"Goal":{"card":{"value":5,"suit":"Black"},"source":{"Bunker":{"slot_index":1}},"goal_slot_index":0}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":4,"pattern":7,"source":{"column":5,"row":6},"destination":{"column":0,"row":2}}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Black"}},"stack_len":3,"pattern":3,"source":{"column":0,"row":3},"destination":{"column":6,"row":1}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":0,"row":2},"destination":{"column":5,"row":6}}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Green"}},"stack_len":4,"pattern":5,"source":{"column":1,"row":3},"destination":{"column":5,"row":7}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":5,"pattern":10,"source":{"column":5,"row":6},"destination":{"column":0,"row":2}}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":0,"row":6},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":4,"pattern":2,"source":{"column":0,"row":2},"destination":{"column":5,"row":6}}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Green"}},"stack_len":3,"pattern":1,"source":{"column":5,"row":7},"destination":{"column":1,"row":3}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Green"}},"stack_len":4,"pattern":6,"source":{"column":6,"row":0},"destination":{"column":0,"row":2}}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":1,"row":6},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":2,"field_position":{"column":6,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":0,"row":5},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Black"}},"stack_len":2,"pattern":1,"source":{"column":0,"row":3},"destination":{"column":5,"row":7}}},{"Bunkerize":{"card":{"Number":{"value":7,"suit":"Green"}},"bunker_slot_index":2,"field_position":{"column":0,"row":2},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":5,"row":9},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":0,"row":1},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Red"}},"stack_len":6,"pattern":23,"source":{"column":1,"row":1},"destination":{"column":0,"row":1}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Green"}},"stack_len":5,"pattern":15,"source":{"column":5,"row":5},"destination":{"column":1,"row":1}}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":5,"row":5},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":7,"suit":"Green"}},"bunker_slot_index":2,"field_position":{"column":5,"row":6},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":0,"row":6},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Red"}},"bunker_slot_index":2,"field_position":{"column":1,"row":5},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":0,"row":6},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":1,"field_position":{"column":2,"row":2},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Red"}},"bunker_slot_index":2,"field_position":{"column":1,"row":5},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":2,"field_position":{"column":2,"row":1},"to_bunker":true}},{"Goal":{"card":{"value":3,"suit":"Green"},"source":{"Field":{"column":2,"row":0}},"goal_slot_index":1}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":1,"field_position":{"column":2,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":4,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":9,"suit":"Red"}},"stack_len":3,"pattern":3,"source":{"column":5,"row":4},"destination":{"column":4,"row":0}}},{"DragonKill":{"card":"Zhong","source":[{"Bunker":{"slot_index":1}},{"Bunker":{"slot_index":2}},{"Field":{"column":5,"row":3}},{"Field":{"column":7,"row":0}}],"destination_slot_index":1}},{"Goal":{"card":{"value":2,"suit":"Red"},"source":{"Field":{"column":5,"row":2}},"goal_slot_index":2}},{"Goal":{"card":{"value":3,"suit":"Red"},"source":{"Field":{"column":0,"row":6}},"goal_slot_index":2}},{"Goal":{"card":{"value":4,"suit":"Green"},"source":{"Field":{"column":0,"row":5}},"goal_slot_index":1}},{"Goal":{"card":{"value":4,"suit":"Red"},"source":{"Field":{"column":1,"row":5}},"goal_slot_index":2}},{"Goal":{"card":{"value":5,"suit":"Red"},"source":{"Field":{"column":0,"row":4}},"goal_slot_index":2}},{"Goal":{"card":{"value":5,"suit":"Green"},"source":{"Field":{"column":1,"row":4}},"goal_slot_index":1}},{"Goal":{"card":{"value":6,"suit":"Green"},"source":{"Field":{"column":0,"row":3}},"goal_slot_index":1}},{"Goal":{"card":{"value":6,"suit":"Black"},"source":{"Field":{"column":1,"row":3}},"goal_slot_index":0}},{"DragonKill":{"card":"Fa","source":[{"Field":{"column":2,"row":0}},{"Field":{"column":3,"row":0}},{"Field":{"column":5,"row":1}},{"Field":{"column":6,"row":0}}],"destination_slot_index":2}},{"Goal":{"card":{"value":6,"suit":"Red"},"source":{"Field":{"column":5,"row":0}},"goal_slot_index":2}},{"Goal":{"card":{"value":7,"suit":"Black"},"source":{"Field":{"column":0,"row":2}},"goal_slot_index":0}},{"Goal":{"card":{"value":7,"suit":"Red"},"source":{"Field":{"column":1,"row":2}},"goal_slot_index":2}},{"Goal":{"card":{"value":7,"suit":"Green"},"source":{"Field":{"column":4,"row":2}},"goal_slot_index":1}},{"Goal":{"card":{"value":8,"suit":"Red"},"source":{"Field":{"column":0,"row":1}},"goal_slot_index":2}},{"Goal":{"card":{"value":8,"suit":"Green"},"source":{"Field":{"column":1,"row":1}},"goal_slot_index":1}},{"Goal":{"card":{"value":8,"suit":"Black"},"source":{"Field":{"column":4,"row":1}},"goal_slot_index":0}},{"Goal":{"card":{"value":9,"suit":"Green"},"source":{"Field":{"column":0,"row":0}},"goal_slot_index":1}},{"Goal":{"card":{"value":9,"suit":"Black"},"source":{"Field":{"column":1,"row":0}},"goal_slot_index":0}},{"Goal":{"card":{"value":9,"suit":"Red"},"source":{"Field":{"column":4,"row":0}},"goal_slot_index":2}}] \ No newline at end of file diff --git a/solver-rs/aux/actions/06.json b/solver-rs/aux/actions/06.json new file mode 100644 index 0000000..1c1006b --- /dev/null +++ b/solver-rs/aux/actions/06.json @@ -0,0 +1 @@ +[{"Move":{"start_card":{"Number":{"value":3,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":2,"row":3},"destination":{"column":6,"row":5}}},{"Move":{"start_card":{"Number":{"value":2,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":3,"row":4},"destination":{"column":6,"row":6}}},{"Move":{"start_card":{"Number":{"value":4,"suit":"Black"}},"stack_len":3,"pattern":3,"source":{"column":6,"row":4},"destination":{"column":5,"row":5}}},{"Bunkerize":{"card":{"Number":{"value":9,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":0,"row":4},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":0,"row":3},"destination":{"column":1,"row":5}}},{"Goal":{"card":{"value":2,"suit":"Green"},"source":{"Field":{"column":0,"row":2}},"goal_slot_index":0}},{"Goal":{"card":{"value":1,"suit":"Red"},"source":{"Field":{"column":0,"row":1}},"goal_slot_index":1}},{"Goal":{"card":{"value":2,"suit":"Red"},"source":{"Field":{"column":5,"row":7}},"goal_slot_index":1}},{"Goal":{"card":{"value":3,"suit":"Green"},"source":{"Field":{"column":5,"row":6}},"goal_slot_index":0}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":7,"row":4},"destination":{"column":1,"row":6}}},{"Goal":{"card":{"value":4,"suit":"Green"},"source":{"Field":{"column":7,"row":3}},"goal_slot_index":0}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":9,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":7,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":1,"row":6},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":9,"suit":"Green"}},"bunker_slot_index":2,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":9,"suit":"Red"}},"stack_len":2,"pattern":0,"source":{"column":1,"row":4},"destination":{"column":0,"row":0}}},{"Goal":{"card":{"value":1,"suit":"Black"},"source":{"Field":{"column":1,"row":3}},"goal_slot_index":2}},{"Goal":{"card":{"value":2,"suit":"Black"},"source":{"Bunker":{"slot_index":1}},"goal_slot_index":2}},{"Bunkerize":{"card":{"Number":{"value":7,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":0,"row":2},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Green"}},"stack_len":2,"pattern":0,"source":{"column":0,"row":1},"destination":{"column":1,"row":3}}},{"Bunkerize":{"card":{"Number":{"value":9,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":9,"suit":"Green"}},"bunker_slot_index":2,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":7,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":1,"row":4},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":9,"suit":"Green"}},"bunker_slot_index":2,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":9,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":2,"row":2},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":7,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":1,"row":4},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":9,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":9,"suit":"Green"}},"bunker_slot_index":2,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":2,"row":1},"destination":{"column":0,"row":1}}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Red"}},"bunker_slot_index":2,"field_position":{"column":0,"row":1},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":2,"row":0},"destination":{"column":0,"row":1}}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":2,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":0,"row":1},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Red"}},"bunker_slot_index":2,"field_position":{"column":0,"row":1},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":2,"field_position":{"column":2,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":9,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":2,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":2,"row":1},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":0,"row":1},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":7,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":1,"row":4},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":0,"row":1},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":1,"row":3},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":7,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":0,"row":2},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Red"}},"stack_len":2,"pattern":1,"source":{"column":0,"row":1},"destination":{"column":1,"row":3}}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":2,"row":1},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":2,"row":1},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":0,"row":1},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":7,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":1,"row":4},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":1,"row":3},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":7,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":2,"row":2},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":3,"row":3},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":1,"row":3},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":3,"row":2},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":3,"row":1},"destination":{"column":2,"row":3}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Black"}},"stack_len":2,"pattern":0,"source":{"column":2,"row":2},"destination":{"column":1,"row":4}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":3,"row":0},"destination":{"column":0,"row":2}}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":3,"row":0},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Green"}},"stack_len":2,"pattern":0,"source":{"column":5,"row":4},"destination":{"column":1,"row":6}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Black"}},"stack_len":4,"pattern":0,"source":{"column":1,"row":4},"destination":{"column":2,"row":2}}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":1,"row":3},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Green"}},"stack_len":5,"pattern":0,"source":{"column":2,"row":1},"destination":{"column":1,"row":3}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Black"}},"stack_len":2,"pattern":0,"source":{"column":0,"row":1},"destination":{"column":2,"row":1}}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":0,"row":1},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":1,"row":7},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":1,"row":7},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Black"}},"stack_len":4,"pattern":4,"source":{"column":1,"row":4},"destination":{"column":0,"row":2}}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":3,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":3,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":0,"row":5},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Black"}},"stack_len":3,"pattern":0,"source":{"column":0,"row":2},"destination":{"column":1,"row":4}}},{"Move":{"start_card":{"Number":{"value":4,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":3,"row":0},"destination":{"column":1,"row":7}}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":3,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":1,"row":7},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":4,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":3,"row":0},"destination":{"column":1,"row":7}}},{"Move":{"start_card":{"Special":"Bai"},"stack_len":1,"pattern":0,"source":{"column":5,"row":3},"destination":{"column":3,"row":0}}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Green"}},"stack_len":2,"pattern":1,"source":{"column":1,"row":6},"destination":{"column":5,"row":3}}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Black"}},"stack_len":3,"pattern":3,"source":{"column":5,"row":2},"destination":{"column":2,"row":3}}},{"Goal":{"card":{"value":3,"suit":"Red"},"source":{"Field":{"column":5,"row":1}},"goal_slot_index":1}},{"Goal":{"card":{"value":4,"suit":"Red"},"source":{"Field":{"column":2,"row":5}},"goal_slot_index":1}},{"Goal":{"card":{"value":5,"suit":"Green"},"source":{"Field":{"column":2,"row":4}},"goal_slot_index":0}},{"Goal":{"card":{"value":6,"suit":"Green"},"source":{"Field":{"column":5,"row":0}},"goal_slot_index":0}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":5,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":0,"row":1},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Black"}},"stack_len":3,"pattern":2,"source":{"column":2,"row":1},"destination":{"column":0,"row":1}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Green"}},"stack_len":3,"pattern":0,"source":{"column":1,"row":3},"destination":{"column":2,"row":1}}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":1,"row":3},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":0,"field_position":{"column":3,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":3,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":5,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":0,"field_position":{"column":5,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":3,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":9,"suit":"Black"}},"stack_len":2,"pattern":0,"source":{"column":1,"row":2},"destination":{"column":3,"row":0}}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":1,"row":1},"destination":{"column":2,"row":4}}},{"Goal":{"card":{"value":5,"suit":"Red"},"source":{"Field":{"column":1,"row":0}},"goal_slot_index":1}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":1,"row":0},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Black"}},"stack_len":3,"pattern":2,"source":{"column":2,"row":2},"destination":{"column":3,"row":2}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":2,"pattern":1,"source":{"column":0,"row":2},"destination":{"column":2,"row":2}}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":0,"row":1},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Red"}},"stack_len":4,"pattern":5,"source":{"column":3,"row":1},"destination":{"column":0,"row":1}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Green"}},"stack_len":3,"pattern":3,"source":{"column":2,"row":1},"destination":{"column":3,"row":1}}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":2,"row":1},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":1,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":1,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":1,"field_position":{"column":5,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":5,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":1,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":2,"field_position":{"column":1,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":2,"field_position":{"column":6,"row":3},"to_bunker":true}},{"Goal":{"card":{"value":3,"suit":"Black"},"source":{"Field":{"column":6,"row":2}},"goal_slot_index":2}},{"HuaKill":{"field_position":{"column":6,"row":1}}},{"Goal":{"card":{"value":4,"suit":"Black"},"source":{"Bunker":{"slot_index":0}},"goal_slot_index":2}},{"Goal":{"card":{"value":5,"suit":"Black"},"source":{"Field":{"column":0,"row":4}},"goal_slot_index":2}},{"Goal":{"card":{"value":6,"suit":"Red"},"source":{"Field":{"column":0,"row":3}},"goal_slot_index":1}},{"Goal":{"card":{"value":6,"suit":"Black"},"source":{"Field":{"column":3,"row":3}},"goal_slot_index":2}},{"Goal":{"card":{"value":7,"suit":"Black"},"source":{"Field":{"column":0,"row":2}},"goal_slot_index":2}},{"Goal":{"card":{"value":7,"suit":"Red"},"source":{"Field":{"column":3,"row":2}},"goal_slot_index":1}},{"Goal":{"card":{"value":8,"suit":"Red"},"source":{"Field":{"column":0,"row":1}},"goal_slot_index":1}},{"Goal":{"card":{"value":8,"suit":"Black"},"source":{"Field":{"column":2,"row":1}},"goal_slot_index":2}},{"Goal":{"card":{"value":9,"suit":"Red"},"source":{"Field":{"column":2,"row":0}},"goal_slot_index":1}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":1,"field_position":{"column":2,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":9,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":2,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":1,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":9,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":1,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Green"}},"bunker_slot_index":2,"field_position":{"column":3,"row":1},"to_bunker":true}},{"Goal":{"card":{"value":9,"suit":"Black"},"source":{"Field":{"column":3,"row":0}},"goal_slot_index":2}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":0,"field_position":{"column":4,"row":4},"to_bunker":true}},{"Move":{"start_card":{"Special":"Fa"},"stack_len":1,"pattern":0,"source":{"column":4,"row":3},"destination":{"column":3,"row":0}}},{"DragonKill":{"card":"Zhong","source":[{"Bunker":{"slot_index":1}},{"Field":{"column":4,"row":2}},{"Field":{"column":5,"row":0}},{"Field":{"column":7,"row":2}}],"destination_slot_index":1}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":0,"field_position":{"column":5,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":9,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":1,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Green"}},"bunker_slot_index":2,"field_position":{"column":1,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":2,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":9,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":3,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":2,"field_position":{"column":3,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":2,"field_position":{"column":4,"row":1},"to_bunker":true}},{"Goal":{"card":{"value":7,"suit":"Green"},"source":{"Field":{"column":4,"row":0}},"goal_slot_index":0}},{"Goal":{"card":{"value":8,"suit":"Green"},"source":{"Field":{"column":1,"row":0}},"goal_slot_index":0}},{"Goal":{"card":{"value":9,"suit":"Green"},"source":{"Field":{"column":0,"row":0}},"goal_slot_index":0}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":7,"row":1},"to_bunker":true}},{"DragonKill":{"card":"Fa","source":[{"Bunker":{"slot_index":0}},{"Field":{"column":0,"row":0}},{"Field":{"column":6,"row":0}},{"Field":{"column":7,"row":0}}],"destination_slot_index":0}},{"DragonKill":{"card":"Bai","source":[{"Bunker":{"slot_index":2}},{"Field":{"column":2,"row":0}},{"Field":{"column":3,"row":0}},{"Field":{"column":5,"row":0}}],"destination_slot_index":2}}] \ No newline at end of file diff --git a/solver-rs/aux/actions/07.json b/solver-rs/aux/actions/07.json new file mode 100644 index 0000000..f664277 --- /dev/null +++ b/solver-rs/aux/actions/07.json @@ -0,0 +1 @@ +[{"Move":{"start_card":{"Number":{"value":7,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":3,"row":4},"destination":{"column":4,"row":5}}},{"Move":{"start_card":{"Number":{"value":3,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":6,"row":4},"destination":{"column":7,"row":5}}},{"Move":{"start_card":{"Number":{"value":4,"suit":"Black"}},"stack_len":2,"pattern":0,"source":{"column":7,"row":4},"destination":{"column":5,"row":5}}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":0,"field_position":{"column":0,"row":4},"to_bunker":true}},{"Goal":{"card":{"value":1,"suit":"Green"},"source":{"Field":{"column":0,"row":3}},"goal_slot_index":0}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":0,"row":2},"to_bunker":true}},{"Goal":{"card":{"value":1,"suit":"Red"},"source":{"Field":{"column":0,"row":1}},"goal_slot_index":1}},{"Goal":{"card":{"value":2,"suit":"Red"},"source":{"Bunker":{"slot_index":1}},"goal_slot_index":1}},{"Goal":{"card":{"value":3,"suit":"Red"},"source":{"Field":{"column":5,"row":6}},"goal_slot_index":1}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":0,"row":0},"destination":{"column":2,"row":5}}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":1,"row":4},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":1,"row":3},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":2,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":1,"row":2},"to_bunker":true}},{"Goal":{"card":{"value":1,"suit":"Black"},"source":{"Field":{"column":1,"row":1}},"goal_slot_index":2}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Black"}},"stack_len":2,"pattern":1,"source":{"column":2,"row":4},"destination":{"column":1,"row":1}}},{"Move":{"start_card":{"Number":{"value":3,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":0,"row":0},"destination":{"column":2,"row":4}}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Red"}},"stack_len":2,"pattern":1,"source":{"column":5,"row":4},"destination":{"column":0,"row":0}}},{"Move":{"start_card":{"Number":{"value":3,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":5,"row":3},"destination":{"column":0,"row":2}}},{"Goal":{"card":{"value":2,"suit":"Black"},"source":{"Field":{"column":5,"row":2}},"goal_slot_index":2}},{"Goal":{"card":{"value":3,"suit":"Black"},"source":{"Field":{"column":2,"row":4}},"goal_slot_index":2}},{"Goal":{"card":{"value":4,"suit":"Red"},"source":{"Field":{"column":2,"row":3}},"goal_slot_index":1}},{"Goal":{"card":{"value":2,"suit":"Green"},"source":{"Field":{"column":2,"row":2}},"goal_slot_index":0}},{"Goal":{"card":{"value":3,"suit":"Green"},"source":{"Field":{"column":0,"row":2}},"goal_slot_index":0}},{"Goal":{"card":{"value":4,"suit":"Black"},"source":{"Field":{"column":0,"row":1}},"goal_slot_index":2}},{"Goal":{"card":{"value":5,"suit":"Red"},"source":{"Field":{"column":0,"row":0}},"goal_slot_index":1}},{"Goal":{"card":{"value":6,"suit":"Red"},"source":{"Field":{"column":2,"row":1}},"goal_slot_index":1}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":2,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":1,"field_position":{"column":2,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":6,"row":3},"to_bunker":true}},{"Goal":{"card":{"value":7,"suit":"Red"},"source":{"Field":{"column":6,"row":2}},"goal_slot_index":1}},{"Goal":{"card":{"value":4,"suit":"Green"},"source":{"Field":{"column":6,"row":1}},"goal_slot_index":0}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":6,"row":0},"destination":{"column":1,"row":3}}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":6,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":1,"field_position":{"column":2,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":2,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":2,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Green"}},"bunker_slot_index":2,"field_position":{"column":2,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Black"}},"stack_len":3,"pattern":1,"source":{"column":1,"row":1},"destination":{"column":2,"row":0}}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Green"}},"bunker_slot_index":2,"field_position":{"column":1,"row":1},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":2,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":7,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":4,"row":5},"to_bunker":true}},{"Goal":{"card":{"value":8,"suit":"Red"},"source":{"Field":{"column":4,"row":4}},"goal_slot_index":1}},{"Bunkerize":{"card":{"Number":{"value":7,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":1,"row":2},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":1,"field_position":{"column":3,"row":3},"to_bunker":true}},{"DragonKill":{"card":"Fa","source":[{"Bunker":{"slot_index":2}},{"Field":{"column":3,"row":2}},{"Field":{"column":4,"row":3}},{"Field":{"column":6,"row":0}}],"destination_slot_index":2}},{"Goal":{"card":{"value":5,"suit":"Green"},"source":{"Field":{"column":3,"row":1}},"goal_slot_index":0}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":6,"row":0},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Green"}},"stack_len":2,"pattern":0,"source":{"column":1,"row":1},"destination":{"column":4,"row":3}}},{"Goal":{"card":{"value":9,"suit":"Red"},"source":{"Field":{"column":1,"row":0}},"goal_slot_index":1}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":1,"field_position":{"column":1,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":2,"row":2},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":0,"field_position":{"column":1,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":9,"suit":"Black"}},"stack_len":3,"pattern":1,"source":{"column":4,"row":2},"destination":{"column":1,"row":0}}},{"Goal":{"card":{"value":5,"suit":"Black"},"source":{"Field":{"column":4,"row":1}},"goal_slot_index":2}},{"HuaKill":{"field_position":{"column":4,"row":0}}},{"Goal":{"card":{"value":6,"suit":"Black"},"source":{"Field":{"column":0,"row":0}},"goal_slot_index":2}},{"Goal":{"card":{"value":7,"suit":"Black"},"source":{"Field":{"column":1,"row":2}},"goal_slot_index":2}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":1,"field_position":{"column":4,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":1,"row":1},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":9,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":1,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":1,"field_position":{"column":1,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Green"}},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Special":"Bai"},"stack_len":1,"pattern":0,"source":{"column":7,"row":3},"destination":{"column":0,"row":0}}},{"Goal":{"card":{"value":6,"suit":"Green"},"source":{"Field":{"column":7,"row":2}},"goal_slot_index":0}},{"Goal":{"card":{"value":7,"suit":"Green"},"source":{"Field":{"column":2,"row":1}},"goal_slot_index":0}},{"Goal":{"card":{"value":8,"suit":"Green"},"source":{"Bunker":{"slot_index":1}},"goal_slot_index":0}},{"Goal":{"card":{"value":8,"suit":"Black"},"source":{"Field":{"column":2,"row":0}},"goal_slot_index":2}},{"Goal":{"card":{"value":9,"suit":"Black"},"source":{"Bunker":{"slot_index":0}},"goal_slot_index":2}},{"Goal":{"card":{"value":9,"suit":"Green"},"source":{"Field":{"column":3,"row":0}},"goal_slot_index":0}},{"Move":{"start_card":{"Special":"Zhong"},"stack_len":1,"pattern":0,"source":{"column":5,"row":1},"destination":{"column":2,"row":0}}},{"DragonKill":{"card":"Zhong","source":[{"Field":{"column":2,"row":0}},{"Field":{"column":5,"row":0}},{"Field":{"column":6,"row":0}},{"Field":{"column":7,"row":1}}],"destination_slot_index":0}},{"DragonKill":{"card":"Bai","source":[{"Field":{"column":0,"row":0}},{"Field":{"column":1,"row":0}},{"Field":{"column":4,"row":0}},{"Field":{"column":7,"row":0}}],"destination_slot_index":1}}] \ No newline at end of file diff --git a/solver-rs/aux/actions/08.json b/solver-rs/aux/actions/08.json new file mode 100644 index 0000000..bb17021 --- /dev/null +++ b/solver-rs/aux/actions/08.json @@ -0,0 +1 @@ +[{"Move":{"start_card":{"Number":{"value":7,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":0,"row":4},"destination":{"column":1,"row":5}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Red"}},"stack_len":2,"pattern":1,"source":{"column":1,"row":4},"destination":{"column":6,"row":5}}},{"HuaKill":{"field_position":{"column":1,"row":3}}},{"Move":{"start_card":{"Number":{"value":4,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":1,"row":2},"destination":{"column":5,"row":4}}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":0,"field_position":{"column":0,"row":3},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":4,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":1,"row":1},"destination":{"column":0,"row":3}}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":0,"row":3},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":4,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":3,"row":4},"destination":{"column":0,"row":3}}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Red"}},"bunker_slot_index":2,"field_position":{"column":0,"row":3},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":0,"row":3},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":1,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":0,"field_position":{"column":1,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":0,"row":3},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Red"}},"bunker_slot_index":2,"field_position":{"column":0,"row":3},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":2,"field_position":{"column":1,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":1,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":0,"field_position":{"column":3,"row":3},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":3,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":3,"row":2},"destination":{"column":1,"row":1}}},{"Goal":{"card":{"value":3,"suit":"Green"},"source":{"Field":{"column":3,"row":1}},"goal_slot_index":0}},{"Goal":{"card":{"value":4,"suit":"Green"},"source":{"Field":{"column":5,"row":4}},"goal_slot_index":0}},{"Move":{"start_card":{"Number":{"value":4,"suit":"Black"}},"stack_len":2,"pattern":0,"source":{"column":1,"row":0},"destination":{"column":5,"row":4}}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":0,"field_position":{"column":1,"row":0},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":3,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":3,"row":0},"destination":{"column":0,"row":4}}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":3,"row":0},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":2,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":7,"row":4},"destination":{"column":5,"row":6}}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Green"}},"stack_len":3,"pattern":3,"source":{"column":0,"row":2},"destination":{"column":7,"row":4}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":4,"row":4},"destination":{"column":0,"row":2}}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Red"}},"stack_len":4,"pattern":6,"source":{"column":7,"row":3},"destination":{"column":6,"row":7}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Black"}},"stack_len":5,"pattern":12,"source":{"column":6,"row":6},"destination":{"column":0,"row":3}}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":0,"row":7},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Black"}},"stack_len":4,"pattern":4,"source":{"column":0,"row":3},"destination":{"column":6,"row":6}}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Green"}},"bunker_slot_index":1,"field_position":{"column":0,"row":2},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":6,"row":10},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":9,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":0,"row":1},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":2,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":0,"row":0},"destination":{"column":6,"row":11}}},{"Bunkerize":{"card":{"Number":{"value":9,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Green"}},"bunker_slot_index":1,"field_position":{"column":0,"row":1},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Black"}},"stack_len":6,"pattern":12,"source":{"column":6,"row":6},"destination":{"column":0,"row":2}}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":0,"row":7},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":1,"field_position":{"column":1,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":0,"row":7},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Green"}},"stack_len":7,"pattern":24,"source":{"column":0,"row":1},"destination":{"column":1,"row":0}}},{"Bunkerize":{"card":{"Number":{"value":9,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":3,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":9,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":3,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Red"}},"stack_len":5,"pattern":6,"source":{"column":1,"row":2},"destination":{"column":0,"row":0}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Green"}},"stack_len":2,"pattern":0,"source":{"column":1,"row":0},"destination":{"column":3,"row":1}}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Green"}},"stack_len":4,"pattern":3,"source":{"column":0,"row":1},"destination":{"column":1,"row":0}}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":0,"row":0},"destination":{"column":3,"row":3}}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Black"}},"stack_len":2,"pattern":0,"source":{"column":3,"row":2},"destination":{"column":6,"row":6}}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":4,"suit":"Red"}},"stack_len":3,"pattern":1,"source":{"column":1,"row":1},"destination":{"column":0,"row":0}}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":1,"row":0},"destination":{"column":6,"row":8}}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":0,"field_position":{"column":1,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":0,"row":2},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":4,"suit":"Red"}},"stack_len":2,"pattern":1,"source":{"column":0,"row":0},"destination":{"column":6,"row":9}}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":2,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":6,"row":11},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":3,"row":1},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":2,"field_position":{"column":4,"row":3},"to_bunker":true}},{"Goal":{"card":{"value":1,"suit":"Black"},"source":{"Field":{"column":4,"row":2}},"goal_slot_index":1}},{"Goal":{"card":{"value":2,"suit":"Black"},"source":{"Field":{"column":5,"row":6}},"goal_slot_index":1}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":3,"row":1},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":7,"row":2},"to_bunker":true}},{"DragonKill":{"card":"Fa","source":[{"Bunker":{"slot_index":0}},{"Field":{"column":2,"row":3}},{"Field":{"column":4,"row":1}},{"Field":{"column":7,"row":1}}],"destination_slot_index":0}},{"Goal":{"card":{"value":1,"suit":"Red"},"source":{"Field":{"column":7,"row":0}},"goal_slot_index":2}},{"Goal":{"card":{"value":2,"suit":"Red"},"source":{"Field":{"column":6,"row":11}},"goal_slot_index":2}},{"Goal":{"card":{"value":3,"suit":"Red"},"source":{"Field":{"column":5,"row":5}},"goal_slot_index":2}},{"Goal":{"card":{"value":3,"suit":"Black"},"source":{"Field":{"column":6,"row":10}},"goal_slot_index":1}},{"Goal":{"card":{"value":4,"suit":"Black"},"source":{"Field":{"column":5,"row":4}},"goal_slot_index":1}},{"Goal":{"card":{"value":4,"suit":"Red"},"source":{"Field":{"column":6,"row":9}},"goal_slot_index":2}},{"Goal":{"card":{"value":5,"suit":"Red"},"source":{"Field":{"column":5,"row":3}},"goal_slot_index":2}},{"Goal":{"card":{"value":5,"suit":"Green"},"source":{"Field":{"column":6,"row":8}},"goal_slot_index":0}},{"Goal":{"card":{"value":6,"suit":"Red"},"source":{"Field":{"column":6,"row":7}},"goal_slot_index":2}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":7,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":2,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":2,"field_position":{"column":1,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Special":"Bai"},"stack_len":1,"pattern":0,"source":{"column":2,"row":2},"destination":{"column":1,"row":0}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":5,"row":2},"destination":{"column":2,"row":2}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Black"}},"stack_len":2,"pattern":1,"source":{"column":2,"row":1},"destination":{"column":5,"row":2}}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":2,"row":0},"destination":{"column":5,"row":4}}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":1,"field_position":{"column":2,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":2,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":2,"field_position":{"column":4,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":9,"suit":"Green"}},"stack_len":4,"pattern":2,"source":{"column":5,"row":1},"destination":{"column":4,"row":0}}},{"Goal":{"card":{"value":7,"suit":"Red"},"source":{"Field":{"column":5,"row":0}},"goal_slot_index":2}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":5,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":2,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":7,"suit":"Black"}},"bunker_slot_index":2,"field_position":{"column":6,"row":6},"to_bunker":true}},{"Goal":{"card":{"value":8,"suit":"Red"},"source":{"Field":{"column":6,"row":5}},"goal_slot_index":2}},{"Bunkerize":{"card":{"Number":{"value":7,"suit":"Black"}},"bunker_slot_index":2,"field_position":{"column":3,"row":2},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":2,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":5,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":9,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":6,"row":4},"destination":{"column":5,"row":0}}},{"DragonKill":{"card":"Zhong","source":[{"Bunker":{"slot_index":1}},{"Bunker":{"slot_index":2}},{"Field":{"column":6,"row":3}},{"Field":{"column":7,"row":0}}],"destination_slot_index":1}},{"Goal":{"card":{"value":6,"suit":"Green"},"source":{"Field":{"column":6,"row":2}},"goal_slot_index":0}},{"Goal":{"card":{"value":5,"suit":"Black"},"source":{"Field":{"column":6,"row":1}},"goal_slot_index":1}},{"Goal":{"card":{"value":6,"suit":"Black"},"source":{"Field":{"column":4,"row":3}},"goal_slot_index":1}},{"Goal":{"card":{"value":7,"suit":"Black"},"source":{"Field":{"column":3,"row":2}},"goal_slot_index":1}},{"Goal":{"card":{"value":7,"suit":"Green"},"source":{"Field":{"column":4,"row":2}},"goal_slot_index":0}},{"Goal":{"card":{"value":8,"suit":"Green"},"source":{"Field":{"column":3,"row":1}},"goal_slot_index":0}},{"Goal":{"card":{"value":8,"suit":"Black"},"source":{"Field":{"column":4,"row":1}},"goal_slot_index":1}},{"Goal":{"card":{"value":9,"suit":"Red"},"source":{"Field":{"column":3,"row":0}},"goal_slot_index":2}},{"Goal":{"card":{"value":9,"suit":"Green"},"source":{"Field":{"column":4,"row":0}},"goal_slot_index":0}},{"Goal":{"card":{"value":9,"suit":"Black"},"source":{"Field":{"column":5,"row":0}},"goal_slot_index":1}},{"DragonKill":{"card":"Bai","source":[{"Field":{"column":0,"row":0}},{"Field":{"column":1,"row":0}},{"Field":{"column":2,"row":0}},{"Field":{"column":6,"row":0}}],"destination_slot_index":2}}] \ No newline at end of file diff --git a/solver-rs/aux/actions/09.json b/solver-rs/aux/actions/09.json new file mode 100644 index 0000000..643d74e --- /dev/null +++ b/solver-rs/aux/actions/09.json @@ -0,0 +1 @@ +[{"Move":{"start_card":{"Number":{"value":4,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":0,"row":4},"destination":{"column":7,"row":5}}},{"Move":{"start_card":{"Number":{"value":3,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":2,"row":4},"destination":{"column":7,"row":6}}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Green"}},"stack_len":4,"pattern":7,"source":{"column":7,"row":3},"destination":{"column":4,"row":5}}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Red"}},"stack_len":3,"pattern":3,"source":{"column":4,"row":6},"destination":{"column":7,"row":3}}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":0,"row":3},"to_bunker":true}},{"Goal":{"card":{"value":2,"suit":"Red"},"source":{"Field":{"column":0,"row":2}},"goal_slot_index":0}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":0,"row":1},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":0,"row":1},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Green"}},"stack_len":2,"pattern":1,"source":{"column":0,"row":0},"destination":{"column":3,"row":5}}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":1,"row":3},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":0,"field_position":{"column":1,"row":2},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":3,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":0,"row":0},"destination":{"column":1,"row":2}}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":1,"row":2},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":2,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":1,"row":2},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":3,"row":6},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Black"}},"stack_len":4,"pattern":6,"source":{"column":7,"row":2},"destination":{"column":3,"row":6}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Red"}},"stack_len":6,"pattern":24,"source":{"column":3,"row":4},"destination":{"column":7,"row":2}}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":7,"row":7},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Red"}},"stack_len":2,"pattern":1,"source":{"column":7,"row":5},"destination":{"column":4,"row":6}}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":3,"row":4},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":7,"row":4},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":7,"row":4},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":4,"pattern":6,"source":{"column":4,"row":4},"destination":{"column":0,"row":0}}},{"Move":{"start_card":{"Number":{"value":3,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":4,"row":3},"destination":{"column":0,"row":4}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":5,"pattern":6,"source":{"column":0,"row":0},"destination":{"column":4,"row":3}}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Goal":{"card":{"value":3,"suit":"Red"},"source":{"Field":{"column":4,"row":7}},"goal_slot_index":0}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":3,"row":4},"to_bunker":true}},{"Goal":{"card":{"value":4,"suit":"Red"},"source":{"Field":{"column":3,"row":3}},"goal_slot_index":0}},{"Goal":{"card":{"value":1,"suit":"Black"},"source":{"Field":{"column":3,"row":2}},"goal_slot_index":1}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":4,"row":7},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":3,"row":1},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":2,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":3,"row":0},"destination":{"column":1,"row":3}}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":3,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":7,"row":4},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":7,"row":4},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":3,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":2,"field_position":{"column":3,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Red"}},"bunker_slot_index":2,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":5,"row":4},"to_bunker":true}},{"DragonKill":{"card":"Zhong","source":[{"Bunker":{"slot_index":1}},{"Field":{"column":0,"row":0}},{"Field":{"column":2,"row":3}},{"Field":{"column":5,"row":3}}],"destination_slot_index":1}},{"Goal":{"card":{"value":1,"suit":"Green"},"source":{"Field":{"column":5,"row":2}},"goal_slot_index":2}},{"Goal":{"card":{"value":2,"suit":"Green"},"source":{"Field":{"column":1,"row":3}},"goal_slot_index":2}},{"Goal":{"card":{"value":3,"suit":"Green"},"source":{"Field":{"column":4,"row":7}},"goal_slot_index":2}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":2,"row":2},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Red"}},"bunker_slot_index":2,"field_position":{"column":2,"row":2},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":2,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Black"}},"stack_len":2,"pattern":0,"source":{"column":2,"row":1},"destination":{"column":0,"row":0}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Green"}},"stack_len":5,"pattern":13,"source":{"column":4,"row":2},"destination":{"column":2,"row":1}}},{"DragonKill":{"card":"Fa","source":[{"Bunker":{"slot_index":0}},{"Bunker":{"slot_index":2}},{"Field":{"column":4,"row":1}},{"Field":{"column":5,"row":1}}],"destination_slot_index":0}},{"Goal":{"card":{"value":2,"suit":"Black"},"source":{"Field":{"column":4,"row":0}},"goal_slot_index":1}},{"Goal":{"card":{"value":3,"suit":"Black"},"source":{"Field":{"column":1,"row":2}},"goal_slot_index":1}},{"Goal":{"card":{"value":4,"suit":"Green"},"source":{"Field":{"column":1,"row":1}},"goal_slot_index":2}},{"Goal":{"card":{"value":4,"suit":"Black"},"source":{"Field":{"column":2,"row":5}},"goal_slot_index":1}},{"Goal":{"card":{"value":5,"suit":"Red"},"source":{"Field":{"column":2,"row":4}},"goal_slot_index":0}},{"Goal":{"card":{"value":5,"suit":"Black"},"source":{"Field":{"column":5,"row":0}},"goal_slot_index":1}},{"Goal":{"card":{"value":6,"suit":"Red"},"source":{"Field":{"column":0,"row":1}},"goal_slot_index":0}},{"Goal":{"card":{"value":6,"suit":"Black"},"source":{"Field":{"column":7,"row":4}},"goal_slot_index":1}},{"Goal":{"card":{"value":7,"suit":"Black"},"source":{"Field":{"column":0,"row":0}},"goal_slot_index":1}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Green"}},"stack_len":3,"pattern":1,"source":{"column":2,"row":1},"destination":{"column":0,"row":0}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":2,"pattern":0,"source":{"column":0,"row":1},"destination":{"column":4,"row":0}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":0,"row":0},"destination":{"column":2,"row":1}}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":4,"row":1},"destination":{"column":0,"row":0}}},{"Goal":{"card":{"value":7,"suit":"Red"},"source":{"Field":{"column":4,"row":0}},"goal_slot_index":0}},{"Move":{"start_card":{"Special":"Bai"},"stack_len":1,"pattern":0,"source":{"column":6,"row":3},"destination":{"column":4,"row":0}}},{"Goal":{"card":{"value":8,"suit":"Black"},"source":{"Field":{"column":6,"row":2}},"goal_slot_index":1}},{"Goal":{"card":{"value":9,"suit":"Black"},"source":{"Field":{"column":6,"row":1}},"goal_slot_index":1}},{"DragonKill":{"card":"Bai","source":[{"Field":{"column":1,"row":0}},{"Field":{"column":3,"row":0}},{"Field":{"column":4,"row":0}},{"Field":{"column":6,"row":0}}],"destination_slot_index":2}},{"Move":{"start_card":{"Number":{"value":9,"suit":"Green"}},"stack_len":3,"pattern":1,"source":{"column":7,"row":1},"destination":{"column":1,"row":0}}},{"Goal":{"card":{"value":5,"suit":"Green"},"source":{"Field":{"column":7,"row":0}},"goal_slot_index":2}},{"Goal":{"card":{"value":6,"suit":"Green"},"source":{"Field":{"column":0,"row":0}},"goal_slot_index":2}},{"Goal":{"card":{"value":7,"suit":"Green"},"source":{"Field":{"column":1,"row":2}},"goal_slot_index":2}},{"Goal":{"card":{"value":8,"suit":"Red"},"source":{"Field":{"column":1,"row":1}},"goal_slot_index":0}},{"Goal":{"card":{"value":8,"suit":"Green"},"source":{"Field":{"column":2,"row":1}},"goal_slot_index":2}},{"Goal":{"card":{"value":9,"suit":"Green"},"source":{"Field":{"column":1,"row":0}},"goal_slot_index":2}},{"Goal":{"card":{"value":9,"suit":"Red"},"source":{"Field":{"column":2,"row":0}},"goal_slot_index":0}}] \ No newline at end of file diff --git a/solver-rs/aux/actions/10.json b/solver-rs/aux/actions/10.json new file mode 100644 index 0000000..228b089 --- /dev/null +++ b/solver-rs/aux/actions/10.json @@ -0,0 +1 @@ +[{"Move":{"start_card":{"Number":{"value":4,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":4,"row":4},"destination":{"column":5,"row":5}}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":4,"row":3},"destination":{"column":1,"row":5}}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":4,"row":2},"destination":{"column":7,"row":5}}},{"Goal":{"card":{"value":2,"suit":"Black"},"source":{"Field":{"column":4,"row":1}},"goal_slot_index":0}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Green"}},"stack_len":2,"pattern":1,"source":{"column":5,"row":4},"destination":{"column":1,"row":6}}},{"HuaKill":{"field_position":{"column":5,"row":3}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Green"}},"stack_len":2,"pattern":0,"source":{"column":7,"row":4},"destination":{"column":2,"row":5}}},{"Goal":{"card":{"value":1,"suit":"Green"},"source":{"Field":{"column":7,"row":3}},"goal_slot_index":1}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Black"}},"stack_len":4,"pattern":4,"source":{"column":1,"row":4},"destination":{"column":7,"row":3}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Black"}},"stack_len":3,"pattern":1,"source":{"column":2,"row":4},"destination":{"column":1,"row":4}}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":0,"row":4},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":0,"row":3},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":0,"row":2},"destination":{"column":1,"row":7}}},{"Move":{"start_card":{"Number":{"value":3,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":0,"row":1},"destination":{"column":7,"row":7}}},{"Move":{"start_card":{"Number":{"value":2,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":4,"row":0},"destination":{"column":7,"row":8}}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":4,"row":0},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":4,"suit":"Red"}},"stack_len":3,"pattern":2,"source":{"column":7,"row":6},"destination":{"column":6,"row":5}}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":5,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":1,"row":7},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":7,"row":5},"destination":{"column":1,"row":7}}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Black"}},"stack_len":4,"pattern":4,"source":{"column":6,"row":4},"destination":{"column":7,"row":5}}},{"Goal":{"card":{"value":3,"suit":"Black"},"source":{"Field":{"column":6,"row":3}},"goal_slot_index":0}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Black"}},"stack_len":6,"pattern":18,"source":{"column":7,"row":3},"destination":{"column":6,"row":3}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Green"}},"stack_len":3,"pattern":2,"source":{"column":1,"row":5},"destination":{"column":7,"row":3}}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":2,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":1,"row":4},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Red"}},"stack_len":4,"pattern":4,"source":{"column":7,"row":2},"destination":{"column":1,"row":4}}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":7,"row":2},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":5,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":1,"field_position":{"column":3,"row":3},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":4,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":3,"row":2},"destination":{"column":0,"row":1}}},{"Move":{"start_card":{"Number":{"value":3,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":5,"row":2},"destination":{"column":0,"row":2}}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Red"}},"stack_len":3,"pattern":2,"source":{"column":0,"row":0},"destination":{"column":5,"row":2}}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":3,"row":1},"to_bunker":true}},{"DragonKill":{"card":"Zhong","source":[{"Bunker":{"slot_index":0}},{"Bunker":{"slot_index":2}},{"Field":{"column":2,"row":3}},{"Field":{"column":3,"row":0}}],"destination_slot_index":0}},{"Goal":{"card":{"value":2,"suit":"Green"},"source":{"Field":{"column":2,"row":2}},"goal_slot_index":1}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":1,"field_position":{"column":3,"row":0},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Green"}},"stack_len":7,"pattern":36,"source":{"column":6,"row":2},"destination":{"column":2,"row":2}}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":9,"suit":"Green"}},"stack_len":5,"pattern":9,"source":{"column":1,"row":3},"destination":{"column":0,"row":0}}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Black"}},"stack_len":2,"pattern":1,"source":{"column":0,"row":3},"destination":{"column":1,"row":3}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":0,"row":2},"destination":{"column":7,"row":3}}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Red"}},"stack_len":5,"pattern":9,"source":{"column":2,"row":4},"destination":{"column":7,"row":4}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":2,"row":3},"destination":{"column":0,"row":2}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":3,"pattern":3,"source":{"column":1,"row":2},"destination":{"column":2,"row":3}}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Green"}},"stack_len":4,"pattern":5,"source":{"column":5,"row":1},"destination":{"column":0,"row":3}}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":2,"field_position":{"column":1,"row":1},"to_bunker":true}},{"Goal":{"card":{"value":1,"suit":"Red"},"source":{"Field":{"column":1,"row":0}},"goal_slot_index":2}},{"Goal":{"card":{"value":2,"suit":"Red"},"source":{"Field":{"column":7,"row":8}},"goal_slot_index":2}},{"Goal":{"card":{"value":3,"suit":"Red"},"source":{"Field":{"column":0,"row":6}},"goal_slot_index":2}},{"Goal":{"card":{"value":3,"suit":"Green"},"source":{"Field":{"column":7,"row":7}},"goal_slot_index":1}},{"Goal":{"card":{"value":4,"suit":"Green"},"source":{"Field":{"column":0,"row":5}},"goal_slot_index":1}},{"Goal":{"card":{"value":4,"suit":"Red"},"source":{"Field":{"column":7,"row":6}},"goal_slot_index":2}},{"Goal":{"card":{"value":5,"suit":"Red"},"source":{"Field":{"column":0,"row":4}},"goal_slot_index":2}},{"Goal":{"card":{"value":5,"suit":"Green"},"source":{"Field":{"column":2,"row":5}},"goal_slot_index":1}},{"Goal":{"card":{"value":6,"suit":"Green"},"source":{"Field":{"column":0,"row":3}},"goal_slot_index":1}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":1,"field_position":{"column":1,"row":0},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Red"}},"stack_len":2,"pattern":1,"source":{"column":7,"row":4},"destination":{"column":0,"row":3}}},{"Goal":{"card":{"value":7,"suit":"Green"},"source":{"Field":{"column":7,"row":3}},"goal_slot_index":1}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":2,"pattern":1,"source":{"column":2,"row":3},"destination":{"column":7,"row":3}}},{"Goal":{"card":{"value":8,"suit":"Green"},"source":{"Field":{"column":2,"row":2}},"goal_slot_index":1}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Red"}},"stack_len":4,"pattern":5,"source":{"column":0,"row":1},"destination":{"column":2,"row":2}}},{"Goal":{"card":{"value":9,"suit":"Green"},"source":{"Field":{"column":0,"row":0}},"goal_slot_index":1}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":2,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":1,"field_position":{"column":1,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":9,"suit":"Black"}},"stack_len":5,"pattern":10,"source":{"column":2,"row":1},"destination":{"column":1,"row":0}}},{"Goal":{"card":{"value":4,"suit":"Black"},"source":{"Field":{"column":2,"row":0}},"goal_slot_index":0}},{"Goal":{"card":{"value":5,"suit":"Black"},"source":{"Field":{"column":1,"row":4}},"goal_slot_index":0}},{"Goal":{"card":{"value":6,"suit":"Red"},"source":{"Field":{"column":1,"row":3}},"goal_slot_index":2}},{"Goal":{"card":{"value":6,"suit":"Black"},"source":{"Field":{"column":7,"row":4}},"goal_slot_index":0}},{"Goal":{"card":{"value":7,"suit":"Black"},"source":{"Field":{"column":1,"row":2}},"goal_slot_index":0}},{"Goal":{"card":{"value":7,"suit":"Red"},"source":{"Field":{"column":7,"row":3}},"goal_slot_index":2}},{"Goal":{"card":{"value":8,"suit":"Red"},"source":{"Field":{"column":1,"row":1}},"goal_slot_index":2}},{"Goal":{"card":{"value":8,"suit":"Black"},"source":{"Field":{"column":7,"row":2}},"goal_slot_index":0}},{"Goal":{"card":{"value":9,"suit":"Black"},"source":{"Field":{"column":1,"row":0}},"goal_slot_index":0}},{"Goal":{"card":{"value":9,"suit":"Red"},"source":{"Field":{"column":7,"row":1}},"goal_slot_index":2}},{"DragonKill":{"card":"Bai","source":[{"Field":{"column":0,"row":0}},{"Field":{"column":3,"row":0}},{"Field":{"column":6,"row":1}},{"Field":{"column":7,"row":0}}],"destination_slot_index":2}},{"DragonKill":{"card":"Fa","source":[{"Bunker":{"slot_index":1}},{"Field":{"column":4,"row":0}},{"Field":{"column":5,"row":0}},{"Field":{"column":6,"row":0}}],"destination_slot_index":1}}] \ No newline at end of file diff --git a/solver-rs/aux/actions/11.json b/solver-rs/aux/actions/11.json new file mode 100644 index 0000000..19c784d --- /dev/null +++ b/solver-rs/aux/actions/11.json @@ -0,0 +1 @@ +[{"Move":{"start_card":{"Number":{"value":6,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":0,"row":4},"destination":{"column":1,"row":5}}},{"Bunkerize":{"card":{"Number":{"value":5,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":0,"row":3},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":1,"field_position":{"column":0,"row":2},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":0,"row":1},"destination":{"column":2,"row":5}}},{"Bunkerize":{"card":{"Number":{"value":5,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":0,"row":1},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":5,"row":4},"destination":{"column":2,"row":6}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Green"}},"stack_len":2,"pattern":0,"source":{"column":2,"row":5},"destination":{"column":4,"row":5}}},{"Bunkerize":{"card":{"Number":{"value":5,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":0,"row":1},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Black"}},"bunker_slot_index":2,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":5,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":1,"row":5},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Black"}},"bunker_slot_index":2,"field_position":{"column":1,"row":5},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":4,"row":7},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":0,"row":0},"destination":{"column":1,"row":6}}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Green"}},"stack_len":3,"pattern":0,"source":{"column":4,"row":5},"destination":{"column":2,"row":5}}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Green"}},"stack_len":3,"pattern":0,"source":{"column":1,"row":4},"destination":{"column":0,"row":0}}},{"Move":{"start_card":{"Number":{"value":2,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":1,"row":3},"destination":{"column":3,"row":5}}},{"Bunkerize":{"card":{"Number":{"value":5,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":0,"row":2},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Red"}},"bunker_slot_index":2,"field_position":{"column":2,"row":7},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":5,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":0,"row":2},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":3,"row":5},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Red"}},"bunker_slot_index":2,"field_position":{"column":2,"row":7},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Green"}},"bunker_slot_index":2,"field_position":{"column":3,"row":4},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":3,"row":4},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":6,"row":4},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Green"}},"bunker_slot_index":2,"field_position":{"column":6,"row":4},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":4,"suit":"Black"}},"stack_len":2,"pattern":1,"source":{"column":6,"row":3},"destination":{"column":0,"row":3}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Green"}},"stack_len":5,"pattern":12,"source":{"column":0,"row":0},"destination":{"column":6,"row":3}}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Red"}},"stack_len":6,"pattern":24,"source":{"column":6,"row":2},"destination":{"column":4,"row":5}}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":2,"row":7},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":2,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":3,"row":4},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":2,"row":7},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":6,"row":1},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":2,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":6,"row":0},"destination":{"column":4,"row":11}}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":6,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":3,"row":4},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":2,"row":7},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":5,"row":3},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":3,"suit":"Black"}},"stack_len":2,"pattern":0,"source":{"column":3,"row":3},"destination":{"column":5,"row":3}}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":3,"row":2},"destination":{"column":2,"row":7}}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":3,"row":1},"destination":{"column":0,"row":1}}},{"Goal":{"card":{"value":1,"suit":"Red"},"source":{"Field":{"column":3,"row":0}},"goal_slot_index":0}},{"Goal":{"card":{"value":2,"suit":"Red"},"source":{"Field":{"column":5,"row":4}},"goal_slot_index":0}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":3,"row":0},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Red"}},"stack_len":4,"pattern":3,"source":{"column":4,"row":8},"destination":{"column":2,"row":8}}},{"Move":{"start_card":{"Number":{"value":4,"suit":"Black"}},"stack_len":3,"pattern":1,"source":{"column":2,"row":9},"destination":{"column":0,"row":2}}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Green"}},"stack_len":4,"pattern":2,"source":{"column":0,"row":1},"destination":{"column":4,"row":8}}},{"Move":{"start_card":{"Number":{"value":4,"suit":"Green"}},"stack_len":2,"pattern":0,"source":{"column":5,"row":2},"destination":{"column":2,"row":9}}},{"Goal":{"card":{"value":1,"suit":"Black"},"source":{"Field":{"column":5,"row":1}},"goal_slot_index":1}},{"Goal":{"card":{"value":2,"suit":"Black"},"source":{"Field":{"column":4,"row":11}},"goal_slot_index":1}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Green"}},"stack_len":3,"pattern":2,"source":{"column":4,"row":8},"destination":{"column":0,"row":1}}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Red"}},"stack_len":3,"pattern":0,"source":{"column":2,"row":8},"destination":{"column":4,"row":8}}},{"Move":{"start_card":{"Number":{"value":2,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":5,"row":0},"destination":{"column":4,"row":11}}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":1,"field_position":{"column":5,"row":0},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Red"}},"stack_len":4,"pattern":4,"source":{"column":4,"row":8},"destination":{"column":2,"row":8}}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":0,"row":3},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Green"}},"stack_len":2,"pattern":0,"source":{"column":0,"row":1},"destination":{"column":4,"row":8}}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":4,"row":10},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":2,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":2,"row":11},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":2,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":3,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":2,"field_position":{"column":3,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Green"}},"bunker_slot_index":2,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Green"}},"bunker_slot_index":2,"field_position":{"column":2,"row":11},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":3,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":9,"suit":"Red"}},"stack_len":8,"pattern":76,"source":{"column":2,"row":4},"destination":{"column":3,"row":0}}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Red"}},"bunker_slot_index":2,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":1,"field_position":{"column":5,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Red"}},"bunker_slot_index":2,"field_position":{"column":5,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":2,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Special":"Bai"},"stack_len":1,"pattern":0,"source":{"column":2,"row":3},"destination":{"column":0,"row":0}}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":2,"row":2},"destination":{"column":5,"row":1}}},{"DragonKill":{"card":"Fa","source":[{"Bunker":{"slot_index":0}},{"Bunker":{"slot_index":1}},{"Field":{"column":2,"row":1}},{"Field":{"column":6,"row":0}}],"destination_slot_index":0}},{"Goal":{"card":{"value":1,"suit":"Green"},"source":{"Field":{"column":2,"row":0}},"goal_slot_index":2}},{"Goal":{"card":{"value":2,"suit":"Green"},"source":{"Field":{"column":3,"row":7}},"goal_slot_index":2}},{"Goal":{"card":{"value":3,"suit":"Black"},"source":{"Field":{"column":3,"row":6}},"goal_slot_index":1}},{"Goal":{"card":{"value":3,"suit":"Green"},"source":{"Field":{"column":4,"row":10}},"goal_slot_index":2}},{"Goal":{"card":{"value":4,"suit":"Green"},"source":{"Field":{"column":3,"row":5}},"goal_slot_index":2}},{"Goal":{"card":{"value":4,"suit":"Black"},"source":{"Field":{"column":4,"row":9}},"goal_slot_index":1}},{"Goal":{"card":{"value":5,"suit":"Green"},"source":{"Field":{"column":4,"row":8}},"goal_slot_index":2}},{"Goal":{"card":{"value":5,"suit":"Black"},"source":{"Field":{"column":5,"row":1}},"goal_slot_index":1}},{"Goal":{"card":{"value":6,"suit":"Black"},"source":{"Field":{"column":4,"row":7}},"goal_slot_index":1}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":2,"field_position":{"column":2,"row":0},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Green"}},"stack_len":4,"pattern":6,"source":{"column":3,"row":1},"destination":{"column":6,"row":0}}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":9,"suit":"Black"}},"stack_len":3,"pattern":0,"source":{"column":4,"row":4},"destination":{"column":0,"row":0}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Red"}},"stack_len":2,"pattern":0,"source":{"column":0,"row":1},"destination":{"column":4,"row":4}}},{"Bunkerize":{"card":{"Number":{"value":9,"suit":"Black"}},"bunker_slot_index":2,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":2,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":9,"suit":"Black"}},"bunker_slot_index":2,"field_position":{"column":2,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":9,"suit":"Red"}},"bunker_slot_index":2,"field_position":{"column":3,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":3,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":5,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":9,"suit":"Red"}},"bunker_slot_index":2,"field_position":{"column":5,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":4,"row":6},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Red"}},"stack_len":3,"pattern":2,"source":{"column":4,"row":4},"destination":{"column":2,"row":1}}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Green"}},"stack_len":2,"pattern":1,"source":{"column":2,"row":2},"destination":{"column":0,"row":0}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":2,"row":1},"destination":{"column":4,"row":4}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Black"}},"stack_len":3,"pattern":3,"source":{"column":6,"row":1},"destination":{"column":4,"row":5}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Red"}},"stack_len":4,"pattern":7,"source":{"column":4,"row":4},"destination":{"column":2,"row":1}}},{"Bunkerize":{"card":{"Number":{"value":5,"suit":"Red"}},"bunker_slot_index":2,"field_position":{"column":2,"row":4},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Red"}},"stack_len":3,"pattern":3,"source":{"column":2,"row":1},"destination":{"column":4,"row":4}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Black"}},"stack_len":2,"pattern":1,"source":{"column":4,"row":5},"destination":{"column":6,"row":1}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Green"}},"stack_len":3,"pattern":2,"source":{"column":6,"row":0},"destination":{"column":2,"row":1}}},{"Goal":{"card":{"value":6,"suit":"Green"},"source":{"Field":{"column":2,"row":3}},"goal_slot_index":2}},{"Goal":{"card":{"value":7,"suit":"Black"},"source":{"Field":{"column":2,"row":2}},"goal_slot_index":1}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":1,"field_position":{"column":6,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":0,"row":1},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":0,"row":0},"destination":{"column":4,"row":5}}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":3,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":5,"suit":"Red"}},"bunker_slot_index":2,"field_position":{"column":3,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Red"}},"bunker_slot_index":2,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Red"}},"bunker_slot_index":2,"field_position":{"column":4,"row":6},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Green"}},"bunker_slot_index":1,"field_position":{"column":2,"row":1},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":2,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Green"}},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":9,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":2,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":2,"field_position":{"column":2,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Green"}},"bunker_slot_index":2,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Special":"Zhong"},"stack_len":1,"pattern":0,"source":{"column":7,"row":4},"destination":{"column":0,"row":0}}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Green"}},"bunker_slot_index":2,"field_position":{"column":5,"row":1},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":2,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":9,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":5,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":3,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":2,"field_position":{"column":3,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":2,"field_position":{"column":7,"row":3},"to_bunker":true}},{"Goal":{"card":{"value":3,"suit":"Red"},"source":{"Field":{"column":7,"row":2}},"goal_slot_index":0}},{"Goal":{"card":{"value":8,"suit":"Black"},"source":{"Field":{"column":7,"row":1}},"goal_slot_index":1}},{"DragonKill":{"card":"Zhong","source":[{"Bunker":{"slot_index":2}},{"Field":{"column":2,"row":0}},{"Field":{"column":3,"row":0}},{"Field":{"column":7,"row":0}}],"destination_slot_index":2}},{"Goal":{"card":{"value":9,"suit":"Black"},"source":{"Field":{"column":0,"row":0}},"goal_slot_index":1}},{"Bunkerize":{"card":{"Number":{"value":5,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":9,"suit":"Green"}},"stack_len":4,"pattern":5,"source":{"column":4,"row":3},"destination":{"column":2,"row":0}}},{"Goal":{"card":{"value":4,"suit":"Red"},"source":{"Field":{"column":4,"row":2}},"goal_slot_index":0}},{"Goal":{"card":{"value":5,"suit":"Red"},"source":{"Field":{"column":0,"row":0}},"goal_slot_index":0}},{"Goal":{"card":{"value":6,"suit":"Red"},"source":{"Field":{"column":2,"row":3}},"goal_slot_index":0}},{"Goal":{"card":{"value":7,"suit":"Green"},"source":{"Field":{"column":2,"row":2}},"goal_slot_index":2}},{"Goal":{"card":{"value":7,"suit":"Red"},"source":{"Field":{"column":4,"row":1}},"goal_slot_index":0}},{"Goal":{"card":{"value":8,"suit":"Red"},"source":{"Field":{"column":2,"row":1}},"goal_slot_index":0}},{"Goal":{"card":{"value":8,"suit":"Green"},"source":{"Field":{"column":5,"row":1}},"goal_slot_index":2}},{"Goal":{"card":{"value":9,"suit":"Green"},"source":{"Field":{"column":2,"row":0}},"goal_slot_index":2}},{"Goal":{"card":{"value":9,"suit":"Red"},"source":{"Field":{"column":5,"row":0}},"goal_slot_index":0}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":1,"field_position":{"column":1,"row":2},"to_bunker":true}},{"HuaKill":{"field_position":{"column":1,"row":1}}},{"DragonKill":{"card":"Bai","source":[{"Bunker":{"slot_index":1}},{"Field":{"column":1,"row":0}},{"Field":{"column":4,"row":0}},{"Field":{"column":6,"row":0}}],"destination_slot_index":1}}] \ No newline at end of file diff --git a/solver-rs/aux/actions/12.json b/solver-rs/aux/actions/12.json new file mode 100644 index 0000000..3107851 --- /dev/null +++ b/solver-rs/aux/actions/12.json @@ -0,0 +1 @@ +[{"Move":{"start_card":{"Number":{"value":7,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":2,"row":4},"destination":{"column":7,"row":4}}},{"Goal":{"card":{"value":1,"suit":"Green"},"source":{"Field":{"column":2,"row":3}},"goal_slot_index":1}},{"Goal":{"card":{"value":2,"suit":"Green"},"source":{"Field":{"column":3,"row":4}},"goal_slot_index":1}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":4,"row":4},"destination":{"column":7,"row":5}}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":0,"row":4},"to_bunker":true}},{"HuaKill":{"field_position":{"column":0,"row":3}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Red"}},"stack_len":3,"pattern":1,"source":{"column":7,"row":3},"destination":{"column":0,"row":3}}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":0,"row":5},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":4,"row":3},"destination":{"column":0,"row":5}}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":7,"row":3},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Green"}},"bunker_slot_index":1,"field_position":{"column":0,"row":5},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":2,"field_position":{"column":1,"row":4},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":1,"row":4},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Green"}},"bunker_slot_index":1,"field_position":{"column":0,"row":5},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":1,"row":4},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":3,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":2,"row":2},"destination":{"column":1,"row":4}}},{"Goal":{"card":{"value":3,"suit":"Green"},"source":{"Field":{"column":2,"row":1}},"goal_slot_index":1}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Black"}},"stack_len":2,"pattern":1,"source":{"column":0,"row":4},"destination":{"column":2,"row":1}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Green"}},"stack_len":3,"pattern":2,"source":{"column":2,"row":0},"destination":{"column":5,"row":5}}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":2,"row":0},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Green"}},"stack_len":2,"pattern":1,"source":{"column":7,"row":2},"destination":{"column":0,"row":4}}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":0,"row":5},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":1,"row":4},"to_bunker":true}},{"Goal":{"card":{"value":4,"suit":"Green"},"source":{"Field":{"column":1,"row":3}},"goal_slot_index":1}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":0,"row":5},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Red"}},"stack_len":3,"pattern":2,"source":{"column":0,"row":3},"destination":{"column":1,"row":3}}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":2,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":9,"suit":"Black"}},"stack_len":4,"pattern":4,"source":{"column":1,"row":2},"destination":{"column":2,"row":0}}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":1,"row":2},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":1,"field_position":{"column":6,"row":4},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":4,"suit":"Black"}},"stack_len":2,"pattern":0,"source":{"column":1,"row":1},"destination":{"column":6,"row":4}}},{"Goal":{"card":{"value":2,"suit":"Black"},"source":{"Field":{"column":1,"row":0}},"goal_slot_index":0}},{"Goal":{"card":{"value":3,"suit":"Black"},"source":{"Bunker":{"slot_index":0}},"goal_slot_index":0}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":1,"field_position":{"column":1,"row":0},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Green"}},"stack_len":3,"pattern":0,"source":{"column":6,"row":3},"destination":{"column":2,"row":4}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Red"}},"stack_len":6,"pattern":2,"source":{"column":2,"row":1},"destination":{"column":0,"row":3}}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":0,"row":8},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Red"}},"stack_len":5,"pattern":2,"source":{"column":0,"row":3},"destination":{"column":2,"row":1}}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Green"}},"stack_len":2,"pattern":0,"source":{"column":2,"row":4},"destination":{"column":6,"row":3}}},{"Bunkerize":{"card":{"Number":{"value":9,"suit":"Green"}},"bunker_slot_index":1,"field_position":{"column":0,"row":2},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":6,"row":5},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Black"}},"stack_len":4,"pattern":1,"source":{"column":6,"row":2},"destination":{"column":0,"row":2}}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":1,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":5,"pattern":3,"source":{"column":0,"row":1},"destination":{"column":1,"row":0}}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":0,"row":0},"destination":{"column":5,"row":8}}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":1,"row":4},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":4,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":1,"row":3},"destination":{"column":5,"row":9}}},{"Goal":{"card":{"value":5,"suit":"Green"},"source":{"Field":{"column":1,"row":2}},"goal_slot_index":1}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":5,"row":10},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Red"}},"stack_len":3,"pattern":1,"source":{"column":5,"row":8},"destination":{"column":1,"row":2}}},{"Goal":{"card":{"value":6,"suit":"Green"},"source":{"Field":{"column":5,"row":7}},"goal_slot_index":1}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":9,"suit":"Green"}},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":2,"row":3},"to_bunker":true}},{"Goal":{"card":{"value":7,"suit":"Green"},"source":{"Field":{"column":2,"row":2}},"goal_slot_index":1}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":5,"row":7},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":2,"row":1},"destination":{"column":0,"row":1}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Green"}},"stack_len":3,"pattern":0,"source":{"column":5,"row":5},"destination":{"column":2,"row":1}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Black"}},"stack_len":2,"pattern":0,"source":{"column":2,"row":2},"destination":{"column":0,"row":2}}},{"Goal":{"card":{"value":8,"suit":"Green"},"source":{"Field":{"column":2,"row":1}},"goal_slot_index":1}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":0,"row":3},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Red"}},"stack_len":2,"pattern":1,"source":{"column":0,"row":1},"destination":{"column":2,"row":1}}},{"Goal":{"card":{"value":9,"suit":"Green"},"source":{"Field":{"column":0,"row":0}},"goal_slot_index":1}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":2,"row":3},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":1,"row":4},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":2,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":1,"row":4},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":2,"row":3},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":2,"field_position":{"column":3,"row":3},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":2,"row":3},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":3,"row":2},"destination":{"column":2,"row":4}}},{"Goal":{"card":{"value":1,"suit":"Red"},"source":{"Field":{"column":3,"row":1}},"goal_slot_index":2}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":6,"row":1},"to_bunker":true}},{"Goal":{"card":{"value":2,"suit":"Red"},"source":{"Field":{"column":6,"row":0}},"goal_slot_index":2}},{"Goal":{"card":{"value":3,"suit":"Red"},"source":{"Field":{"column":1,"row":4}},"goal_slot_index":2}},{"Goal":{"card":{"value":4,"suit":"Black"},"source":{"Field":{"column":1,"row":3}},"goal_slot_index":0}},{"Goal":{"card":{"value":5,"suit":"Black"},"source":{"Field":{"column":2,"row":4}},"goal_slot_index":0}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":6,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":1,"field_position":{"column":3,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Special":"Zhong"},"stack_len":1,"pattern":0,"source":{"column":7,"row":1},"destination":{"column":3,"row":0}}},{"DragonKill":{"card":"Bai","source":[{"Bunker":{"slot_index":0}},{"Bunker":{"slot_index":1}},{"Bunker":{"slot_index":2}},{"Field":{"column":7,"row":0}}],"destination_slot_index":0}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Black"}},"stack_len":2,"pattern":0,"source":{"column":1,"row":1},"destination":{"column":7,"row":0}}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Special":"Fa"},"stack_len":1,"pattern":0,"source":{"column":4,"row":2},"destination":{"column":0,"row":0}}},{"Bunkerize":{"card":{"Number":{"value":7,"suit":"Red"}},"bunker_slot_index":2,"field_position":{"column":1,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":1,"field_position":{"column":1,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":3,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":7,"suit":"Red"}},"bunker_slot_index":2,"field_position":{"column":3,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":5,"suit":"Red"}},"bunker_slot_index":2,"field_position":{"column":7,"row":1},"to_bunker":true}},{"Goal":{"card":{"value":6,"suit":"Black"},"source":{"Field":{"column":7,"row":0}},"goal_slot_index":0}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":7,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":5,"suit":"Red"}},"bunker_slot_index":2,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":7,"suit":"Red"}},"bunker_slot_index":2,"field_position":{"column":3,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":1,"field_position":{"column":3,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":1,"field_position":{"column":4,"row":1},"to_bunker":true}},{"DragonKill":{"card":"Fa","source":[{"Bunker":{"slot_index":1}},{"Field":{"column":1,"row":0}},{"Field":{"column":3,"row":0}},{"Field":{"column":4,"row":0}}],"destination_slot_index":1}},{"Bunkerize":{"card":{"Number":{"value":7,"suit":"Red"}},"bunker_slot_index":2,"field_position":{"column":1,"row":0},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":9,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":5,"row":4},"destination":{"column":3,"row":0}}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Red"}},"bunker_slot_index":2,"field_position":{"column":2,"row":3},"to_bunker":true}},{"Goal":{"card":{"value":7,"suit":"Black"},"source":{"Field":{"column":2,"row":2}},"goal_slot_index":0}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Red"}},"bunker_slot_index":2,"field_position":{"column":4,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":2,"field_position":{"column":5,"row":3},"to_bunker":true}},{"Goal":{"card":{"value":8,"suit":"Black"},"source":{"Field":{"column":5,"row":2}},"goal_slot_index":0}},{"Goal":{"card":{"value":4,"suit":"Red"},"source":{"Field":{"column":5,"row":1}},"goal_slot_index":2}},{"Goal":{"card":{"value":5,"suit":"Red"},"source":{"Field":{"column":0,"row":0}},"goal_slot_index":2}},{"Goal":{"card":{"value":6,"suit":"Red"},"source":{"Field":{"column":4,"row":0}},"goal_slot_index":2}},{"Goal":{"card":{"value":7,"suit":"Red"},"source":{"Field":{"column":1,"row":0}},"goal_slot_index":2}},{"Goal":{"card":{"value":8,"suit":"Red"},"source":{"Field":{"column":2,"row":1}},"goal_slot_index":2}},{"Goal":{"card":{"value":9,"suit":"Black"},"source":{"Field":{"column":2,"row":0}},"goal_slot_index":0}},{"Goal":{"card":{"value":9,"suit":"Red"},"source":{"Field":{"column":3,"row":0}},"goal_slot_index":2}},{"DragonKill":{"card":"Zhong","source":[{"Bunker":{"slot_index":2}},{"Field":{"column":5,"row":0}},{"Field":{"column":6,"row":0}},{"Field":{"column":7,"row":0}}],"destination_slot_index":2}}] \ No newline at end of file diff --git a/solver-rs/aux/actions/13.json b/solver-rs/aux/actions/13.json new file mode 100644 index 0000000..ef585c9 --- /dev/null +++ b/solver-rs/aux/actions/13.json @@ -0,0 +1 @@ +[{"Move":{"start_card":{"Number":{"value":3,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":4,"row":4},"destination":{"column":6,"row":4}}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":4,"row":3},"destination":{"column":5,"row":5}}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":4,"row":2},"destination":{"column":5,"row":6}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Green"}},"stack_len":3,"pattern":1,"source":{"column":5,"row":4},"destination":{"column":3,"row":5}}},{"Move":{"start_card":{"Number":{"value":4,"suit":"Red"}},"stack_len":2,"pattern":0,"source":{"column":6,"row":3},"destination":{"column":3,"row":8}}},{"Bunkerize":{"card":{"Number":{"value":7,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":0,"row":4},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":9,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":0,"row":3},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":2,"field_position":{"column":4,"row":1},"to_bunker":true}},{"DragonKill":{"card":"Zhong","source":[{"Bunker":{"slot_index":2}},{"Field":{"column":4,"row":0}},{"Field":{"column":5,"row":3}},{"Field":{"column":7,"row":4}}],"destination_slot_index":2}},{"Bunkerize":{"card":{"Number":{"value":7,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":7,"row":4},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":9,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":4,"row":0},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Green"}},"stack_len":3,"pattern":1,"source":{"column":3,"row":7},"destination":{"column":5,"row":3}}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Black"}},"stack_len":4,"pattern":3,"source":{"column":5,"row":2},"destination":{"column":7,"row":5}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Green"}},"stack_len":6,"pattern":15,"source":{"column":7,"row":3},"destination":{"column":4,"row":1}}},{"Move":{"start_card":{"Number":{"value":4,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":0,"row":2},"destination":{"column":7,"row":3}}},{"Move":{"start_card":{"Number":{"value":3,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":0,"row":1},"destination":{"column":6,"row":3}}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Red"}},"stack_len":2,"pattern":1,"source":{"column":7,"row":2},"destination":{"column":5,"row":2}}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Special":"Bai"},"stack_len":1,"pattern":0,"source":{"column":1,"row":4},"destination":{"column":0,"row":0}}},{"Goal":{"card":{"value":1,"suit":"Black"},"source":{"Field":{"column":1,"row":3}},"goal_slot_index":0}},{"Goal":{"card":{"value":2,"suit":"Black"},"source":{"Field":{"column":1,"row":2}},"goal_slot_index":0}},{"Goal":{"card":{"value":3,"suit":"Black"},"source":{"Field":{"column":6,"row":3}},"goal_slot_index":0}},{"Goal":{"card":{"value":4,"suit":"Black"},"source":{"Field":{"column":5,"row":3}},"goal_slot_index":0}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Green"}},"stack_len":2,"pattern":1,"source":{"column":5,"row":1},"destination":{"column":1,"row":2}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Red"}},"stack_len":3,"pattern":2,"source":{"column":3,"row":4},"destination":{"column":5,"row":1}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":5,"pattern":7,"source":{"column":4,"row":2},"destination":{"column":3,"row":4}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Black"}},"stack_len":3,"pattern":3,"source":{"column":1,"row":1},"destination":{"column":4,"row":2}}},{"Goal":{"card":{"value":5,"suit":"Black"},"source":{"Field":{"column":1,"row":0}},"goal_slot_index":0}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":1,"row":0},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":4,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":6,"row":2},"destination":{"column":4,"row":5}}},{"Move":{"start_card":{"Number":{"value":3,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":6,"row":1},"destination":{"column":4,"row":6}}},{"Goal":{"card":{"value":1,"suit":"Red"},"source":{"Field":{"column":6,"row":0}},"goal_slot_index":1}},{"Move":{"start_card":{"Special":"Fa"},"stack_len":1,"pattern":0,"source":{"column":2,"row":4},"destination":{"column":6,"row":0}}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Black"}},"stack_len":6,"pattern":14,"source":{"column":3,"row":3},"destination":{"column":0,"row":0}}},{"Goal":{"card":{"value":2,"suit":"Red"},"source":{"Field":{"column":3,"row":2}},"goal_slot_index":1}},{"Goal":{"card":{"value":3,"suit":"Red"},"source":{"Field":{"column":4,"row":6}},"goal_slot_index":1}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Green"}},"bunker_slot_index":1,"field_position":{"column":0,"row":5},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Green"}},"stack_len":2,"pattern":1,"source":{"column":0,"row":3},"destination":{"column":5,"row":4}}},{"Goal":{"card":{"value":6,"suit":"Black"},"source":{"Field":{"column":0,"row":2}},"goal_slot_index":0}},{"Goal":{"card":{"value":4,"suit":"Red"},"source":{"Field":{"column":5,"row":5}},"goal_slot_index":1}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Green"}},"stack_len":3,"pattern":1,"source":{"column":4,"row":3},"destination":{"column":0,"row":2}}},{"Goal":{"card":{"value":7,"suit":"Black"},"source":{"Field":{"column":4,"row":2}},"goal_slot_index":0}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":4,"pattern":2,"source":{"column":0,"row":1},"destination":{"column":4,"row":2}}},{"Goal":{"card":{"value":8,"suit":"Black"},"source":{"Field":{"column":0,"row":0}},"goal_slot_index":0}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":1,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Green"}},"bunker_slot_index":1,"field_position":{"column":1,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":2,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":3,"row":1},"destination":{"column":0,"row":0}}},{"DragonKill":{"card":"Fa","source":[{"Bunker":{"slot_index":0}},{"Field":{"column":3,"row":0}},{"Field":{"column":6,"row":0}},{"Field":{"column":7,"row":1}}],"destination_slot_index":0}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":1,"field_position":{"column":3,"row":0},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Green"}},"stack_len":5,"pattern":5,"source":{"column":4,"row":1},"destination":{"column":6,"row":0}}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Green"}},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Red"}},"stack_len":4,"pattern":2,"source":{"column":5,"row":1},"destination":{"column":0,"row":0}}},{"Goal":{"card":{"value":9,"suit":"Black"},"source":{"Field":{"column":5,"row":0}},"goal_slot_index":0}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Green"}},"bunker_slot_index":1,"field_position":{"column":5,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Green"}},"bunker_slot_index":1,"field_position":{"column":1,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Red"}},"stack_len":2,"pattern":0,"source":{"column":6,"row":3},"destination":{"column":1,"row":0}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Green"}},"stack_len":3,"pattern":1,"source":{"column":6,"row":0},"destination":{"column":4,"row":1}}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Green"}},"bunker_slot_index":1,"field_position":{"column":6,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Green"}},"bunker_slot_index":1,"field_position":{"column":1,"row":1},"to_bunker":true}},{"Goal":{"card":{"value":5,"suit":"Red"},"source":{"Field":{"column":1,"row":0}},"goal_slot_index":1}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Green"}},"bunker_slot_index":1,"field_position":{"column":1,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":1,"field_position":{"column":2,"row":3},"to_bunker":true}},{"DragonKill":{"card":"Bai","source":[{"Bunker":{"slot_index":1}},{"Field":{"column":2,"row":2}},{"Field":{"column":3,"row":0}},{"Field":{"column":7,"row":0}}],"destination_slot_index":1}},{"Goal":{"card":{"value":1,"suit":"Green"},"source":{"Field":{"column":2,"row":1}},"goal_slot_index":2}},{"Goal":{"card":{"value":2,"suit":"Green"},"source":{"Field":{"column":5,"row":0}},"goal_slot_index":2}},{"Goal":{"card":{"value":3,"suit":"Green"},"source":{"Field":{"column":6,"row":0}},"goal_slot_index":2}},{"Goal":{"card":{"value":4,"suit":"Green"},"source":{"Field":{"column":1,"row":0}},"goal_slot_index":2}},{"Goal":{"card":{"value":5,"suit":"Green"},"source":{"Field":{"column":0,"row":3}},"goal_slot_index":2}},{"Goal":{"card":{"value":6,"suit":"Red"},"source":{"Field":{"column":0,"row":2}},"goal_slot_index":1}},{"Goal":{"card":{"value":6,"suit":"Green"},"source":{"Field":{"column":4,"row":3}},"goal_slot_index":2}},{"Goal":{"card":{"value":7,"suit":"Green"},"source":{"Field":{"column":0,"row":1}},"goal_slot_index":2}},{"Goal":{"card":{"value":7,"suit":"Red"},"source":{"Field":{"column":4,"row":2}},"goal_slot_index":1}},{"Goal":{"card":{"value":8,"suit":"Red"},"source":{"Field":{"column":0,"row":0}},"goal_slot_index":1}},{"Goal":{"card":{"value":8,"suit":"Green"},"source":{"Field":{"column":4,"row":1}},"goal_slot_index":2}},{"Goal":{"card":{"value":9,"suit":"Green"},"source":{"Field":{"column":2,"row":0}},"goal_slot_index":2}},{"Goal":{"card":{"value":9,"suit":"Red"},"source":{"Field":{"column":4,"row":0}},"goal_slot_index":1}}] \ No newline at end of file diff --git a/solver-rs/aux/actions/14.json b/solver-rs/aux/actions/14.json new file mode 100644 index 0000000..13c1daa --- /dev/null +++ b/solver-rs/aux/actions/14.json @@ -0,0 +1 @@ +[{"Move":{"start_card":{"Number":{"value":6,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":0,"row":4},"destination":{"column":6,"row":5}}},{"Move":{"start_card":{"Number":{"value":2,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":0,"row":3},"destination":{"column":1,"row":5}}},{"Move":{"start_card":{"Number":{"value":2,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":0,"row":2},"destination":{"column":2,"row":5}}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":0,"row":1},"destination":{"column":6,"row":6}}},{"Goal":{"card":{"value":1,"suit":"Black"},"source":{"Field":{"column":0,"row":0}},"goal_slot_index":0}},{"Goal":{"card":{"value":2,"suit":"Black"},"source":{"Field":{"column":4,"row":4}},"goal_slot_index":0}},{"Move":{"start_card":{"Number":{"value":3,"suit":"Red"}},"stack_len":2,"pattern":0,"source":{"column":1,"row":4},"destination":{"column":0,"row":0}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":1,"row":3},"destination":{"column":3,"row":5}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":4,"row":3},"destination":{"column":3,"row":6}}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Red"}},"stack_len":2,"pattern":0,"source":{"column":4,"row":1},"destination":{"column":3,"row":7}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Black"}},"stack_len":3,"pattern":0,"source":{"column":3,"row":6},"destination":{"column":5,"row":5}}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":0,"row":1},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":1,"row":2},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Green"}},"bunker_slot_index":2,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":1,"row":1},"to_bunker":true}},{"HuaKill":{"field_position":{"column":1,"row":0}}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":1,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Green"}},"bunker_slot_index":2,"field_position":{"column":0,"row":1},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":1,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":1,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":0,"row":1},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":2,"field_position":{"column":1,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":1,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":5,"suit":"Green"}},"bunker_slot_index":1,"field_position":{"column":5,"row":7},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Black"}},"stack_len":2,"pattern":0,"source":{"column":5,"row":5},"destination":{"column":3,"row":6}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":3,"pattern":2,"source":{"column":6,"row":4},"destination":{"column":5,"row":5}}},{"Bunkerize":{"card":{"Number":{"value":5,"suit":"Green"}},"bunker_slot_index":1,"field_position":{"column":3,"row":8},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":1,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":1,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":0,"row":1},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":2,"row":5},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":1,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":1,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":4,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":2,"field_position":{"column":4,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Red"}},"bunker_slot_index":2,"field_position":{"column":1,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":1,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Red"}},"bunker_slot_index":2,"field_position":{"column":2,"row":5},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":0,"row":1},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Red"}},"bunker_slot_index":2,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":1,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Red"}},"bunker_slot_index":2,"field_position":{"column":1,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":2,"field_position":{"column":4,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Special":"Zhong"},"stack_len":1,"pattern":0,"source":{"column":7,"row":4},"destination":{"column":4,"row":0}}},{"Move":{"start_card":{"Number":{"value":3,"suit":"Green"}},"stack_len":2,"pattern":1,"source":{"column":2,"row":4},"destination":{"column":7,"row":4}}},{"Move":{"start_card":{"Number":{"value":4,"suit":"Red"}},"stack_len":3,"pattern":2,"source":{"column":7,"row":3},"destination":{"column":3,"row":9}}},{"Goal":{"card":{"value":3,"suit":"Black"},"source":{"Field":{"column":7,"row":2}},"goal_slot_index":0}},{"Move":{"start_card":{"Number":{"value":3,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":1,"row":0},"destination":{"column":7,"row":2}}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":1,"row":0},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Red"}},"stack_len":5,"pattern":10,"source":{"column":3,"row":7},"destination":{"column":2,"row":4}}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Green"}},"stack_len":2,"pattern":1,"source":{"column":5,"row":6},"destination":{"column":3,"row":7}}},{"Move":{"start_card":{"Number":{"value":4,"suit":"Black"}},"stack_len":2,"pattern":0,"source":{"column":7,"row":1},"destination":{"column":3,"row":9}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Green"}},"stack_len":6,"pattern":21,"source":{"column":2,"row":3},"destination":{"column":7,"row":1}}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Green"}},"stack_len":4,"pattern":3,"source":{"column":3,"row":7},"destination":{"column":5,"row":6}}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":5,"row":10},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Green"}},"stack_len":5,"pattern":3,"source":{"column":5,"row":6},"destination":{"column":3,"row":7}}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":3,"row":11},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":2,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":3,"row":11},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":1,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Red"}},"stack_len":7,"pattern":15,"source":{"column":3,"row":5},"destination":{"column":1,"row":0}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Black"}},"stack_len":7,"pattern":43,"source":{"column":7,"row":0},"destination":{"column":3,"row":5}}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":7,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Green"}},"bunker_slot_index":1,"field_position":{"column":1,"row":6},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":2,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":3,"row":11},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Green"}},"bunker_slot_index":1,"field_position":{"column":1,"row":6},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":4,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":1,"field_position":{"column":4,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Black"}},"stack_len":6,"pattern":7,"source":{"column":1,"row":1},"destination":{"column":0,"row":0}}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":3,"row":11},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Green"}},"bunker_slot_index":1,"field_position":{"column":0,"row":5},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Black"}},"stack_len":5,"pattern":7,"source":{"column":0,"row":0},"destination":{"column":1,"row":1}}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Red"}},"stack_len":3,"pattern":1,"source":{"column":1,"row":3},"destination":{"column":0,"row":0}}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Green"}},"bunker_slot_index":1,"field_position":{"column":0,"row":3},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":7,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":5,"row":5},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Black"}},"stack_len":2,"pattern":1,"source":{"column":1,"row":1},"destination":{"column":5,"row":5}}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Red"}},"stack_len":4,"pattern":1,"source":{"column":0,"row":0},"destination":{"column":5,"row":7}}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":1,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":7,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":1,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":3,"row":11},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Green"}},"stack_len":5,"pattern":5,"source":{"column":3,"row":6},"destination":{"column":0,"row":1}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":1,"row":0},"destination":{"column":3,"row":6}}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":0,"row":6},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":1,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":0,"row":6},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":1,"field_position":{"column":4,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":0,"row":6},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":2,"field_position":{"column":4,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":0,"row":6},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":7,"suit":"Red"}},"bunker_slot_index":2,"field_position":{"column":3,"row":6},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":0,"row":6},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":1,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":7,"suit":"Red"}},"bunker_slot_index":2,"field_position":{"column":1,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Black"}},"bunker_slot_index":2,"field_position":{"column":3,"row":5},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Red"}},"stack_len":7,"pattern":42,"source":{"column":0,"row":0},"destination":{"column":3,"row":5}}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":7,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":1,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":1,"field_position":{"column":1,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":7,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":4,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Black"}},"bunker_slot_index":2,"field_position":{"column":4,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":7,"suit":"Red"}},"bunker_slot_index":2,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":7,"suit":"Red"}},"bunker_slot_index":2,"field_position":{"column":4,"row":1},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":1,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":1,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":3,"row":11},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":2,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":1,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Green"}},"stack_len":7,"pattern":14,"source":{"column":5,"row":4},"destination":{"column":1,"row":0}}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":3,"row":11},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":5,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":5,"row":3},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Green"}},"stack_len":4,"pattern":5,"source":{"column":3,"row":8},"destination":{"column":5,"row":3}}},{"Bunkerize":{"card":{"Number":{"value":5,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":3,"row":8},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Black"}},"stack_len":5,"pattern":11,"source":{"column":5,"row":2},"destination":{"column":4,"row":2}}},{"DragonKill":{"card":"Zhong","source":[{"Bunker":{"slot_index":0}},{"Bunker":{"slot_index":2}},{"Field":{"column":5,"row":1}},{"Field":{"column":7,"row":0}}],"destination_slot_index":0}},{"Move":{"start_card":{"Number":{"value":4,"suit":"Black"}},"stack_len":3,"pattern":0,"source":{"column":1,"row":4},"destination":{"column":7,"row":0}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Green"}},"stack_len":4,"pattern":6,"source":{"column":1,"row":0},"destination":{"column":5,"row":1}}},{"Move":{"start_card":{"Special":"Bai"},"stack_len":1,"pattern":0,"source":{"column":2,"row":2},"destination":{"column":1,"row":0}}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Special":"Fa"},"stack_len":1,"pattern":0,"source":{"column":2,"row":1},"destination":{"column":0,"row":0}}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":2,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":9,"suit":"Green"}},"stack_len":5,"pattern":13,"source":{"column":3,"row":4},"destination":{"column":0,"row":0}}},{"DragonKill":{"card":"Fa","source":[{"Bunker":{"slot_index":1}},{"Bunker":{"slot_index":2}},{"Field":{"column":3,"row":3}},{"Field":{"column":6,"row":3}}],"destination_slot_index":1}},{"Goal":{"card":{"value":1,"suit":"Red"},"source":{"Field":{"column":3,"row":2}},"goal_slot_index":1}},{"Goal":{"card":{"value":2,"suit":"Red"},"source":{"Field":{"column":4,"row":6}},"goal_slot_index":1}},{"Move":{"start_card":{"Number":{"value":4,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":3,"row":1},"destination":{"column":0,"row":5}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Red"}},"stack_len":5,"pattern":14,"source":{"column":0,"row":1},"destination":{"column":3,"row":1}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Black"}},"stack_len":6,"pattern":14,"source":{"column":4,"row":0},"destination":{"column":0,"row":1}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":5,"pattern":7,"source":{"column":0,"row":2},"destination":{"column":4,"row":0}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Green"}},"stack_len":4,"pattern":7,"source":{"column":3,"row":2},"destination":{"column":0,"row":2}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Black"}},"stack_len":3,"pattern":3,"source":{"column":5,"row":2},"destination":{"column":3,"row":2}}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Green"}},"bunker_slot_index":2,"field_position":{"column":0,"row":5},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":4,"suit":"Red"}},"stack_len":2,"pattern":0,"source":{"column":4,"row":3},"destination":{"column":0,"row":5}}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Green"}},"bunker_slot_index":2,"field_position":{"column":3,"row":5},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Black"}},"stack_len":4,"pattern":3,"source":{"column":3,"row":2},"destination":{"column":5,"row":2}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Green"}},"stack_len":5,"pattern":3,"source":{"column":0,"row":2},"destination":{"column":3,"row":2}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":3,"pattern":3,"source":{"column":4,"row":0},"destination":{"column":0,"row":2}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Black"}},"stack_len":4,"pattern":6,"source":{"column":0,"row":1},"destination":{"column":4,"row":0}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Red"}},"stack_len":6,"pattern":6,"source":{"column":3,"row":1},"destination":{"column":0,"row":1}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Green"}},"stack_len":5,"pattern":6,"source":{"column":5,"row":1},"destination":{"column":3,"row":1}}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Green"}},"bunker_slot_index":2,"field_position":{"column":0,"row":6},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":4,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":0,"row":5},"destination":{"column":4,"row":4}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Black"}},"stack_len":5,"pattern":14,"source":{"column":4,"row":0},"destination":{"column":5,"row":1}}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Green"}},"bunker_slot_index":2,"field_position":{"column":5,"row":6},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Red"}},"stack_len":4,"pattern":6,"source":{"column":0,"row":1},"destination":{"column":4,"row":0}}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":2,"field_position":{"column":1,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Green"}},"stack_len":3,"pattern":1,"source":{"column":3,"row":3},"destination":{"column":1,"row":0}}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Red"}},"stack_len":2,"pattern":1,"source":{"column":4,"row":2},"destination":{"column":3,"row":3}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Red"}},"stack_len":2,"pattern":0,"source":{"column":4,"row":0},"destination":{"column":0,"row":1}}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":2,"field_position":{"column":4,"row":0},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Black"}},"stack_len":4,"pattern":3,"source":{"column":5,"row":3},"destination":{"column":0,"row":3}}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":2,"field_position":{"column":2,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Green"}},"stack_len":3,"pattern":1,"source":{"column":0,"row":4},"destination":{"column":2,"row":0}}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":0,"row":3},"destination":{"column":5,"row":3}}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Red"}},"stack_len":2,"pattern":0,"source":{"column":1,"row":1},"destination":{"column":5,"row":4}}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":3,"row":4},"destination":{"column":1,"row":1}}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":3,"row":3},"destination":{"column":0,"row":3}}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Green"}},"stack_len":2,"pattern":0,"source":{"column":1,"row":0},"destination":{"column":3,"row":3}}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":2,"field_position":{"column":1,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Green"}},"bunker_slot_index":2,"field_position":{"column":2,"row":2},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Green"}},"stack_len":2,"pattern":1,"source":{"column":2,"row":0},"destination":{"column":0,"row":4}}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Green"}},"bunker_slot_index":2,"field_position":{"column":2,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":2,"field_position":{"column":1,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Red"}},"stack_len":5,"pattern":10,"source":{"column":0,"row":1},"destination":{"column":1,"row":0}}},{"Move":{"start_card":{"Number":{"value":3,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":2,"row":0},"destination":{"column":1,"row":5}}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":2,"field_position":{"column":2,"row":0},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Black"}},"stack_len":5,"pattern":2,"source":{"column":5,"row":1},"destination":{"column":0,"row":1}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Green"}},"stack_len":4,"pattern":2,"source":{"column":3,"row":1},"destination":{"column":5,"row":1}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Red"}},"stack_len":6,"pattern":10,"source":{"column":1,"row":0},"destination":{"column":3,"row":1}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":4,"pattern":1,"source":{"column":0,"row":2},"destination":{"column":1,"row":0}}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Green"}},"bunker_slot_index":2,"field_position":{"column":1,"row":3},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":3,"pattern":1,"source":{"column":1,"row":0},"destination":{"column":0,"row":2}}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Green"}},"bunker_slot_index":2,"field_position":{"column":1,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Green"}},"bunker_slot_index":2,"field_position":{"column":7,"row":2},"to_bunker":true}},{"Goal":{"card":{"value":3,"suit":"Red"},"source":{"Field":{"column":7,"row":1}},"goal_slot_index":1}},{"Goal":{"card":{"value":4,"suit":"Black"},"source":{"Field":{"column":7,"row":0}},"goal_slot_index":0}},{"Goal":{"card":{"value":5,"suit":"Black"},"source":{"Field":{"column":5,"row":4}},"goal_slot_index":0}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Green"}},"bunker_slot_index":2,"field_position":{"column":7,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":5,"suit":"Red"}},"bunker_slot_index":2,"field_position":{"column":0,"row":4},"to_bunker":true}},{"Goal":{"card":{"value":6,"suit":"Black"},"source":{"Field":{"column":0,"row":3}},"goal_slot_index":0}},{"Bunkerize":{"card":{"Number":{"value":5,"suit":"Red"}},"bunker_slot_index":2,"field_position":{"column":5,"row":4},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Green"}},"bunker_slot_index":2,"field_position":{"column":1,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Red"}},"stack_len":4,"pattern":2,"source":{"column":3,"row":3},"destination":{"column":1,"row":0}}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Green"}},"bunker_slot_index":2,"field_position":{"column":5,"row":5},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":2,"field_position":{"column":6,"row":2},"to_bunker":true}},{"Goal":{"card":{"value":1,"suit":"Green"},"source":{"Field":{"column":6,"row":1}},"goal_slot_index":2}},{"Goal":{"card":{"value":2,"suit":"Green"},"source":{"Field":{"column":7,"row":0}},"goal_slot_index":2}},{"Goal":{"card":{"value":3,"suit":"Green"},"source":{"Field":{"column":1,"row":3}},"goal_slot_index":2}},{"Goal":{"card":{"value":4,"suit":"Red"},"source":{"Field":{"column":1,"row":2}},"goal_slot_index":1}},{"Goal":{"card":{"value":4,"suit":"Green"},"source":{"Field":{"column":5,"row":5}},"goal_slot_index":2}},{"Goal":{"card":{"value":5,"suit":"Green"},"source":{"Field":{"column":1,"row":1}},"goal_slot_index":2}},{"Goal":{"card":{"value":5,"suit":"Red"},"source":{"Field":{"column":5,"row":4}},"goal_slot_index":1}},{"Goal":{"card":{"value":6,"suit":"Red"},"source":{"Field":{"column":1,"row":0}},"goal_slot_index":1}},{"Goal":{"card":{"value":6,"suit":"Green"},"source":{"Field":{"column":5,"row":3}},"goal_slot_index":2}},{"Goal":{"card":{"value":7,"suit":"Red"},"source":{"Field":{"column":0,"row":2}},"goal_slot_index":1}},{"Goal":{"card":{"value":7,"suit":"Green"},"source":{"Field":{"column":3,"row":2}},"goal_slot_index":2}},{"Goal":{"card":{"value":7,"suit":"Black"},"source":{"Field":{"column":5,"row":2}},"goal_slot_index":0}},{"Goal":{"card":{"value":8,"suit":"Black"},"source":{"Field":{"column":0,"row":1}},"goal_slot_index":0}},{"Goal":{"card":{"value":8,"suit":"Red"},"source":{"Field":{"column":3,"row":1}},"goal_slot_index":1}},{"Goal":{"card":{"value":8,"suit":"Green"},"source":{"Field":{"column":5,"row":1}},"goal_slot_index":2}},{"Goal":{"card":{"value":9,"suit":"Green"},"source":{"Field":{"column":0,"row":0}},"goal_slot_index":2}},{"Goal":{"card":{"value":9,"suit":"Black"},"source":{"Field":{"column":3,"row":0}},"goal_slot_index":0}},{"Goal":{"card":{"value":9,"suit":"Red"},"source":{"Field":{"column":5,"row":0}},"goal_slot_index":1}},{"DragonKill":{"card":"Bai","source":[{"Bunker":{"slot_index":2}},{"Field":{"column":2,"row":0}},{"Field":{"column":4,"row":0}},{"Field":{"column":6,"row":0}}],"destination_slot_index":2}}] \ No newline at end of file diff --git a/solver-rs/aux/actions/15.json b/solver-rs/aux/actions/15.json new file mode 100644 index 0000000..1f70197 --- /dev/null +++ b/solver-rs/aux/actions/15.json @@ -0,0 +1 @@ +[{"Goal":{"card":{"value":3,"suit":"Black"},"source":{"Field":{"column":0,"row":3}},"goal_slot_index":1}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":0,"field_position":{"column":0,"row":2},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":0,"row":1},"destination":{"column":6,"row":5}}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":0,"field_position":{"column":3,"row":4},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":2,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":3,"row":3},"to_bunker":true}},{"DragonKill":{"card":"Bai","source":[{"Bunker":{"slot_index":0}},{"Bunker":{"slot_index":2}},{"Field":{"column":3,"row":2}},{"Field":{"column":7,"row":4}}],"destination_slot_index":0}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":7,"row":4},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":4,"suit":"Green"}},"stack_len":2,"pattern":1,"source":{"column":7,"row":3},"destination":{"column":3,"row":2}}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Black"}},"stack_len":2,"pattern":1,"source":{"column":7,"row":1},"destination":{"column":6,"row":6}}},{"Move":{"start_card":{"Number":{"value":3,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":2,"row":4},"destination":{"column":7,"row":1}}},{"Move":{"start_card":{"Number":{"value":4,"suit":"Red"}},"stack_len":2,"pattern":0,"source":{"column":7,"row":0},"destination":{"column":6,"row":8}}},{"Move":{"start_card":{"Number":{"value":9,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":1,"row":2},"destination":{"column":7,"row":0}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Black"}},"stack_len":6,"pattern":14,"source":{"column":6,"row":4},"destination":{"column":1,"row":2}}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":9,"suit":"Red"}},"stack_len":7,"pattern":29,"source":{"column":1,"row":1},"destination":{"column":0,"row":0}}},{"HuaKill":{"field_position":{"column":1,"row":0}}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":1,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Green"}},"bunker_slot_index":1,"field_position":{"column":0,"row":6},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":2,"field_position":{"column":1,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Green"}},"bunker_slot_index":1,"field_position":{"column":1,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":1,"field_position":{"column":2,"row":3},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":2,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":2,"row":2},"destination":{"column":1,"row":1}}},{"Move":{"start_card":{"Number":{"value":3,"suit":"Green"}},"stack_len":2,"pattern":1,"source":{"column":1,"row":0},"destination":{"column":0,"row":6}}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":1,"field_position":{"column":1,"row":0},"to_bunker":false}},{"Goal":{"card":{"value":2,"suit":"Red"},"source":{"Field":{"column":0,"row":7}},"goal_slot_index":0}},{"Goal":{"card":{"value":3,"suit":"Red"},"source":{"Field":{"column":3,"row":3}},"goal_slot_index":0}},{"Bunkerize":{"card":{"Number":{"value":9,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":7,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Green"}},"stack_len":3,"pattern":1,"source":{"column":0,"row":4},"destination":{"column":7,"row":0}}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Red"}},"stack_len":2,"pattern":0,"source":{"column":3,"row":1},"destination":{"column":0,"row":4}}},{"DragonKill":{"card":"Zhong","source":[{"Bunker":{"slot_index":2}},{"Field":{"column":3,"row":0}},{"Field":{"column":5,"row":4}},{"Field":{"column":6,"row":3}}],"destination_slot_index":2}},{"Goal":{"card":{"value":4,"suit":"Black"},"source":{"Field":{"column":5,"row":3}},"goal_slot_index":1}},{"Bunkerize":{"card":{"Number":{"value":9,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":3,"row":0},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":4,"pattern":1,"source":{"column":0,"row":2},"destination":{"column":6,"row":3}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Green"}},"stack_len":5,"pattern":3,"source":{"column":6,"row":2},"destination":{"column":3,"row":1}}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":1,"field_position":{"column":1,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Special":"Fa"},"stack_len":1,"pattern":0,"source":{"column":2,"row":1},"destination":{"column":1,"row":0}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":2,"row":0},"destination":{"column":0,"row":2}}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":1,"field_position":{"column":2,"row":0},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Black"}},"stack_len":3,"pattern":0,"source":{"column":3,"row":3},"destination":{"column":0,"row":3}}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":1,"field_position":{"column":1,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":5,"row":2},"destination":{"column":1,"row":0}}},{"Goal":{"card":{"value":1,"suit":"Green"},"source":{"Field":{"column":5,"row":1}},"goal_slot_index":2}},{"Goal":{"card":{"value":2,"suit":"Green"},"source":{"Field":{"column":6,"row":1}},"goal_slot_index":2}},{"Goal":{"card":{"value":3,"suit":"Green"},"source":{"Field":{"column":7,"row":2}},"goal_slot_index":2}},{"Goal":{"card":{"value":4,"suit":"Green"},"source":{"Field":{"column":0,"row":5}},"goal_slot_index":2}},{"Goal":{"card":{"value":4,"suit":"Red"},"source":{"Field":{"column":7,"row":1}},"goal_slot_index":0}},{"Goal":{"card":{"value":5,"suit":"Red"},"source":{"Field":{"column":0,"row":4}},"goal_slot_index":0}},{"Goal":{"card":{"value":5,"suit":"Green"},"source":{"Field":{"column":7,"row":0}},"goal_slot_index":2}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":1,"field_position":{"column":7,"row":0},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Black"}},"stack_len":3,"pattern":1,"source":{"column":0,"row":1},"destination":{"column":6,"row":1}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Green"}},"stack_len":2,"pattern":1,"source":{"column":3,"row":1},"destination":{"column":0,"row":1}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":5,"row":0},"destination":{"column":3,"row":1}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Green"}},"stack_len":2,"pattern":0,"source":{"column":6,"row":2},"destination":{"column":3,"row":2}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Red"}},"stack_len":3,"pattern":0,"source":{"column":3,"row":1},"destination":{"column":5,"row":0}}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":5,"row":2},"destination":{"column":0,"row":3}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Green"}},"stack_len":3,"pattern":3,"source":{"column":0,"row":1},"destination":{"column":3,"row":1}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":2,"pattern":1,"source":{"column":3,"row":2},"destination":{"column":6,"row":2}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":3,"row":1},"destination":{"column":0,"row":1}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Red"}},"stack_len":2,"pattern":0,"source":{"column":5,"row":0},"destination":{"column":3,"row":1}}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":1,"field_position":{"column":4,"row":4},"to_bunker":true}},{"Goal":{"card":{"value":5,"suit":"Black"},"source":{"Field":{"column":4,"row":3}},"goal_slot_index":1}},{"Goal":{"card":{"value":6,"suit":"Green"},"source":{"Field":{"column":4,"row":2}},"goal_slot_index":2}},{"Goal":{"card":{"value":6,"suit":"Black"},"source":{"Field":{"column":6,"row":3}},"goal_slot_index":1}},{"DragonKill":{"card":"Fa","source":[{"Bunker":{"slot_index":1}},{"Field":{"column":2,"row":0}},{"Field":{"column":4,"row":1}},{"Field":{"column":7,"row":0}}],"destination_slot_index":1}},{"Goal":{"card":{"value":6,"suit":"Red"},"source":{"Field":{"column":4,"row":0}},"goal_slot_index":0}},{"Goal":{"card":{"value":7,"suit":"Black"},"source":{"Field":{"column":1,"row":0}},"goal_slot_index":1}},{"Goal":{"card":{"value":7,"suit":"Green"},"source":{"Field":{"column":3,"row":2}},"goal_slot_index":2}},{"Goal":{"card":{"value":7,"suit":"Red"},"source":{"Field":{"column":6,"row":2}},"goal_slot_index":0}},{"Goal":{"card":{"value":8,"suit":"Green"},"source":{"Field":{"column":0,"row":1}},"goal_slot_index":2}},{"Goal":{"card":{"value":8,"suit":"Red"},"source":{"Field":{"column":3,"row":1}},"goal_slot_index":0}},{"Goal":{"card":{"value":8,"suit":"Black"},"source":{"Field":{"column":6,"row":1}},"goal_slot_index":1}},{"Goal":{"card":{"value":9,"suit":"Red"},"source":{"Field":{"column":0,"row":0}},"goal_slot_index":0}},{"Goal":{"card":{"value":9,"suit":"Black"},"source":{"Field":{"column":3,"row":0}},"goal_slot_index":1}},{"Goal":{"card":{"value":9,"suit":"Green"},"source":{"Field":{"column":6,"row":0}},"goal_slot_index":2}}] \ No newline at end of file diff --git a/solver-rs/aux/actions/16.json b/solver-rs/aux/actions/16.json new file mode 100644 index 0000000..094cbdd --- /dev/null +++ b/solver-rs/aux/actions/16.json @@ -0,0 +1 @@ +[{"Move":{"start_card":{"Number":{"value":6,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":7,"row":4},"destination":{"column":1,"row":5}}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":0,"row":4},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":4,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":0,"row":3},"destination":{"column":7,"row":4}}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Green"}},"stack_len":2,"pattern":1,"source":{"column":0,"row":1},"destination":{"column":1,"row":6}}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":0,"row":0},"destination":{"column":4,"row":3}}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Red"}},"stack_len":2,"pattern":0,"source":{"column":7,"row":3},"destination":{"column":4,"row":4}}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Red"}},"stack_len":3,"pattern":2,"source":{"column":1,"row":5},"destination":{"column":0,"row":0}}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":0,"row":2},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Red"}},"stack_len":2,"pattern":0,"source":{"column":0,"row":0},"destination":{"column":1,"row":5}}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":5,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":1,"row":6},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":2,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":5,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":0,"row":1},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":1,"row":5},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":2,"row":4},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":1,"row":5},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":0,"row":1},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":0,"row":0},"destination":{"column":1,"row":6}}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":4,"row":5},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":4,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":0,"row":0},"destination":{"column":1,"row":7}}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":9,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":7,"row":2},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":3,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":7,"row":1},"destination":{"column":0,"row":1}}},{"Move":{"start_card":{"Number":{"value":4,"suit":"Green"}},"stack_len":2,"pattern":0,"source":{"column":0,"row":0},"destination":{"column":4,"row":5}}},{"Bunkerize":{"card":{"Number":{"value":9,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":4,"row":6},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":3,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":7,"row":0},"destination":{"column":4,"row":6}}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":1,"row":8},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":7,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":9,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":2,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":1,"row":8},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":2,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":9,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":4,"row":6},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":1,"row":8},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":9,"suit":"Green"}},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":0,"field_position":{"column":5,"row":4},"to_bunker":true}},{"HuaKill":{"field_position":{"column":5,"row":3}}},{"Goal":{"card":{"value":2,"suit":"Red"},"source":{"Field":{"column":5,"row":2}},"goal_slot_index":0}},{"Goal":{"card":{"value":3,"suit":"Red"},"source":{"Field":{"column":0,"row":0}},"goal_slot_index":0}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":1,"row":8},"to_bunker":true}},{"Goal":{"card":{"value":4,"suit":"Red"},"source":{"Field":{"column":1,"row":7}},"goal_slot_index":0}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":4,"row":6},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":9,"suit":"Green"}},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":7,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":0,"field_position":{"column":7,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":9,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":2,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":2,"field_position":{"column":7,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":9,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":6,"row":4},"destination":{"column":7,"row":0}}},{"DragonKill":{"card":"Bai","source":[{"Bunker":{"slot_index":2}},{"Field":{"column":2,"row":3}},{"Field":{"column":5,"row":1}},{"Field":{"column":6,"row":3}}],"destination_slot_index":2}},{"Move":{"start_card":{"Number":{"value":2,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":2,"row":2},"destination":{"column":4,"row":7}}},{"Move":{"start_card":{"Number":{"value":4,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":2,"row":1},"destination":{"column":1,"row":7}}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Red"}},"stack_len":3,"pattern":0,"source":{"column":1,"row":5},"destination":{"column":6,"row":3}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Green"}},"stack_len":5,"pattern":0,"source":{"column":6,"row":1},"destination":{"column":7,"row":1}}},{"Goal":{"card":{"value":2,"suit":"Black"},"source":{"Field":{"column":6,"row":0}},"goal_slot_index":1}},{"Bunkerize":{"card":{"Number":{"value":9,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":6,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":1,"field_position":{"column":3,"row":4},"to_bunker":true}},{"DragonKill":{"card":"Fa","source":[{"Bunker":{"slot_index":0}},{"Bunker":{"slot_index":1}},{"Field":{"column":3,"row":3}},{"Field":{"column":5,"row":0}}],"destination_slot_index":0}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":1,"row":4},"destination":{"column":5,"row":0}}},{"Move":{"start_card":{"Number":{"value":4,"suit":"Green"}},"stack_len":3,"pattern":2,"source":{"column":4,"row":5},"destination":{"column":3,"row":3}}},{"Goal":{"card":{"value":5,"suit":"Red"},"source":{"Field":{"column":4,"row":4}},"goal_slot_index":0}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Black"}},"stack_len":4,"pattern":5,"source":{"column":3,"row":2},"destination":{"column":4,"row":4}}},{"Move":{"start_card":{"Number":{"value":3,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":3,"row":1},"destination":{"column":7,"row":6}}},{"Goal":{"card":{"value":1,"suit":"Green"},"source":{"Field":{"column":3,"row":0}},"goal_slot_index":2}},{"Goal":{"card":{"value":2,"suit":"Green"},"source":{"Field":{"column":4,"row":7}},"goal_slot_index":2}},{"Goal":{"card":{"value":3,"suit":"Black"},"source":{"Field":{"column":4,"row":6}},"goal_slot_index":1}},{"Goal":{"card":{"value":3,"suit":"Green"},"source":{"Field":{"column":7,"row":6}},"goal_slot_index":2}},{"Goal":{"card":{"value":4,"suit":"Green"},"source":{"Field":{"column":4,"row":5}},"goal_slot_index":2}},{"Goal":{"card":{"value":4,"suit":"Black"},"source":{"Field":{"column":7,"row":5}},"goal_slot_index":1}},{"Goal":{"card":{"value":5,"suit":"Black"},"source":{"Field":{"column":4,"row":4}},"goal_slot_index":1}},{"Goal":{"card":{"value":5,"suit":"Green"},"source":{"Field":{"column":7,"row":4}},"goal_slot_index":2}},{"Goal":{"card":{"value":6,"suit":"Green"},"source":{"Field":{"column":4,"row":3}},"goal_slot_index":2}},{"Goal":{"card":{"value":6,"suit":"Red"},"source":{"Field":{"column":7,"row":3}},"goal_slot_index":0}},{"Goal":{"card":{"value":7,"suit":"Red"},"source":{"Field":{"column":4,"row":2}},"goal_slot_index":0}},{"Goal":{"card":{"value":7,"suit":"Green"},"source":{"Field":{"column":5,"row":0}},"goal_slot_index":2}},{"Move":{"start_card":{"Number":{"value":9,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":1,"row":3},"destination":{"column":3,"row":0}}},{"DragonKill":{"card":"Zhong","source":[{"Field":{"column":0,"row":0}},{"Field":{"column":1,"row":2}},{"Field":{"column":2,"row":0}},{"Field":{"column":4,"row":1}}],"destination_slot_index":1}},{"Goal":{"card":{"value":6,"suit":"Black"},"source":{"Field":{"column":1,"row":1}},"goal_slot_index":1}},{"Goal":{"card":{"value":7,"suit":"Black"},"source":{"Field":{"column":7,"row":2}},"goal_slot_index":1}},{"Goal":{"card":{"value":8,"suit":"Black"},"source":{"Field":{"column":1,"row":0}},"goal_slot_index":1}},{"Goal":{"card":{"value":8,"suit":"Red"},"source":{"Field":{"column":4,"row":0}},"goal_slot_index":0}},{"Goal":{"card":{"value":8,"suit":"Green"},"source":{"Field":{"column":7,"row":1}},"goal_slot_index":2}},{"Goal":{"card":{"value":9,"suit":"Black"},"source":{"Field":{"column":3,"row":0}},"goal_slot_index":1}},{"Goal":{"card":{"value":9,"suit":"Green"},"source":{"Field":{"column":6,"row":0}},"goal_slot_index":2}},{"Goal":{"card":{"value":9,"suit":"Red"},"source":{"Field":{"column":7,"row":0}},"goal_slot_index":0}}] \ No newline at end of file diff --git a/solver-rs/aux/actions/17.json b/solver-rs/aux/actions/17.json new file mode 100644 index 0000000..f7c23b3 --- /dev/null +++ b/solver-rs/aux/actions/17.json @@ -0,0 +1 @@ +[{"Move":{"start_card":{"Number":{"value":7,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":1,"row":4},"destination":{"column":7,"row":5}}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":4,"row":4},"destination":{"column":6,"row":5}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Black"}},"stack_len":2,"pattern":1,"source":{"column":7,"row":4},"destination":{"column":0,"row":5}}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":7,"row":3},"destination":{"column":6,"row":6}}},{"Bunkerize":{"card":{"Number":{"value":7,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":0,"row":6},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":3,"pattern":2,"source":{"column":6,"row":4},"destination":{"column":0,"row":6}}},{"Goal":{"card":{"value":1,"suit":"Red"},"source":{"Field":{"column":6,"row":3}},"goal_slot_index":0}},{"Bunkerize":{"card":{"Number":{"value":7,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":6,"row":3},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":5,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":0,"row":8},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Green"}},"bunker_slot_index":1,"field_position":{"column":0,"row":7},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Green"}},"bunker_slot_index":2,"field_position":{"column":1,"row":3},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Green"}},"bunker_slot_index":1,"field_position":{"column":0,"row":7},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":5,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":0,"row":8},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Black"}},"stack_len":4,"pattern":4,"source":{"column":0,"row":5},"destination":{"column":1,"row":3}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Red"}},"stack_len":2,"pattern":0,"source":{"column":6,"row":2},"destination":{"column":0,"row":5}}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Green"}},"bunker_slot_index":2,"field_position":{"column":6,"row":2},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":4,"suit":"Black"}},"stack_len":2,"pattern":1,"source":{"column":6,"row":1},"destination":{"column":1,"row":7}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":5,"pattern":14,"source":{"column":1,"row":4},"destination":{"column":6,"row":1}}},{"Bunkerize":{"card":{"Number":{"value":7,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":0,"row":6},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":0,"row":5},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":7,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":1,"row":4},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":2,"row":4},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Red"}},"bunker_slot_index":1,"field_position":{"column":0,"row":5},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":7,"suit":"Green"}},"bunker_slot_index":1,"field_position":{"column":1,"row":4},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Red"}},"bunker_slot_index":2,"field_position":{"column":0,"row":5},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":1,"row":3},"destination":{"column":0,"row":5}}},{"Bunkerize":{"card":{"Number":{"value":7,"suit":"Green"}},"bunker_slot_index":1,"field_position":{"column":0,"row":6},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Green"}},"stack_len":6,"pattern":29,"source":{"column":6,"row":0},"destination":{"column":1,"row":3}}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":6,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":7,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":0,"row":6},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":0,"row":5},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Red"}},"bunker_slot_index":2,"field_position":{"column":0,"row":5},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":7,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":0,"row":6},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":1,"row":8},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Green"}},"bunker_slot_index":2,"field_position":{"column":2,"row":3},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":1,"row":8},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Red"}},"stack_len":3,"pattern":3,"source":{"column":1,"row":6},"destination":{"column":2,"row":3}}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Black"}},"stack_len":4,"pattern":6,"source":{"column":2,"row":2},"destination":{"column":0,"row":7}}},{"Goal":{"card":{"value":1,"suit":"Green"},"source":{"Field":{"column":2,"row":1}},"goal_slot_index":1}},{"Move":{"start_card":{"Number":{"value":2,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":2,"row":0},"destination":{"column":0,"row":11}}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":2,"row":0},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Green"}},"stack_len":6,"pattern":12,"source":{"column":0,"row":6},"destination":{"column":2,"row":1}}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Red"}},"stack_len":4,"pattern":3,"source":{"column":2,"row":3},"destination":{"column":1,"row":6}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Green"}},"stack_len":2,"pattern":0,"source":{"column":2,"row":1},"destination":{"column":0,"row":6}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":6,"pattern":14,"source":{"column":1,"row":4},"destination":{"column":2,"row":1}}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":0,"row":7},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Green"}},"bunker_slot_index":1,"field_position":{"column":1,"row":3},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":0,"row":7},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Black"}},"stack_len":7,"pattern":28,"source":{"column":2,"row":0},"destination":{"column":1,"row":3}}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Green"}},"bunker_slot_index":1,"field_position":{"column":2,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":0,"row":7},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":1,"row":9},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":0,"row":7},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":1,"row":8},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":4,"pattern":6,"source":{"column":1,"row":4},"destination":{"column":2,"row":1}}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Red"}},"stack_len":2,"pattern":1,"source":{"column":2,"row":3},"destination":{"column":0,"row":8}}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":0,"row":10},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":0,"row":11},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":1,"row":3},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":0,"row":11},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Green"}},"stack_len":3,"pattern":1,"source":{"column":2,"row":0},"destination":{"column":1,"row":3}}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":2,"row":0},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Green"}},"stack_len":5,"pattern":12,"source":{"column":0,"row":6},"destination":{"column":2,"row":1}}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":0,"row":5},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":2,"row":6},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Black"}},"stack_len":7,"pattern":25,"source":{"column":2,"row":0},"destination":{"column":0,"row":5}}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Red"}},"bunker_slot_index":0,"field_position":{"column":2,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":0,"row":11},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Green"}},"bunker_slot_index":1,"field_position":{"column":0,"row":10},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Green"}},"stack_len":4,"pattern":4,"source":{"column":0,"row":6},"destination":{"column":2,"row":1}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":2,"pattern":0,"source":{"column":1,"row":4},"destination":{"column":0,"row":6}}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Green"}},"bunker_slot_index":1,"field_position":{"column":2,"row":5},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":2,"row":6},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":0,"row":7},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":0,"row":6},"destination":{"column":1,"row":4}}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Black"}},"stack_len":5,"pattern":6,"source":{"column":2,"row":2},"destination":{"column":1,"row":5}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":6,"pattern":13,"source":{"column":1,"row":4},"destination":{"column":0,"row":6}}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":6,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":4,"suit":"Black"}},"stack_len":3,"pattern":1,"source":{"column":0,"row":9},"destination":{"column":6,"row":0}}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Green"}},"bunker_slot_index":2,"field_position":{"column":0,"row":9},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":4,"pattern":1,"source":{"column":0,"row":6},"destination":{"column":1,"row":4}}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Black"}},"stack_len":3,"pattern":0,"source":{"column":1,"row":5},"destination":{"column":2,"row":2}}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":1,"row":5},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Green"}},"stack_len":4,"pattern":0,"source":{"column":2,"row":1},"destination":{"column":0,"row":6}}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Red"}},"stack_len":2,"pattern":0,"source":{"column":0,"row":8},"destination":{"column":1,"row":6}}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":0,"row":7},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":7,"suit":"Green"}},"bunker_slot_index":2,"field_position":{"column":0,"row":6},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":4,"pattern":2,"source":{"column":1,"row":4},"destination":{"column":0,"row":6}}},{"Bunkerize":{"card":{"Number":{"value":7,"suit":"Green"}},"bunker_slot_index":2,"field_position":{"column":2,"row":1},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":2,"row":2},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":0,"row":9},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Green"}},"bunker_slot_index":2,"field_position":{"column":1,"row":3},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":0,"row":9},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Black"}},"stack_len":5,"pattern":4,"source":{"column":0,"row":5},"destination":{"column":1,"row":3}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Red"}},"stack_len":3,"pattern":0,"source":{"column":2,"row":0},"destination":{"column":0,"row":5}}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":2,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":0,"row":7},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Green"}},"bunker_slot_index":1,"field_position":{"column":1,"row":7},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":0,"row":7},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":2,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Green"}},"bunker_slot_index":1,"field_position":{"column":2,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":0,"row":7},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":4,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":2,"row":0},"destination":{"column":1,"row":7}}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":2,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":1,"field_position":{"column":4,"row":3},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":2,"row":0},"destination":{"column":0,"row":7}}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":2,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":7,"row":2},"to_bunker":true}},{"DragonKill":{"card":"Fa","source":[{"Bunker":{"slot_index":0}},{"Field":{"column":3,"row":4}},{"Field":{"column":4,"row":2}},{"Field":{"column":7,"row":1}}],"destination_slot_index":0}},{"Goal":{"card":{"value":1,"suit":"Black"},"source":{"Field":{"column":7,"row":0}},"goal_slot_index":2}},{"Goal":{"card":{"value":2,"suit":"Black"},"source":{"Field":{"column":6,"row":2}},"goal_slot_index":2}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":1,"field_position":{"column":7,"row":0},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Green"}},"stack_len":3,"pattern":1,"source":{"column":1,"row":5},"destination":{"column":4,"row":2}}},{"Move":{"start_card":{"Number":{"value":3,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":6,"row":1},"destination":{"column":3,"row":4}}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":2,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":8,"suit":"Green"}},"bunker_slot_index":2,"field_position":{"column":2,"row":0},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Black"}},"stack_len":4,"pattern":3,"source":{"column":4,"row":1},"destination":{"column":2,"row":1}}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Green"}},"bunker_slot_index":2,"field_position":{"column":2,"row":4},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Green"}},"stack_len":2,"pattern":1,"source":{"column":2,"row":2},"destination":{"column":1,"row":5}}},{"Move":{"start_card":{"Number":{"value":4,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":6,"row":0},"destination":{"column":1,"row":7}}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":6,"row":0},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Green"}},"stack_len":3,"pattern":3,"source":{"column":1,"row":5},"destination":{"column":2,"row":2}}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":2,"row":4},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Green"}},"bunker_slot_index":2,"field_position":{"column":2,"row":4},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":2,"field_position":{"column":4,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":4,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":6,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":9,"suit":"Green"}},"stack_len":4,"pattern":1,"source":{"column":0,"row":4},"destination":{"column":6,"row":0}}},{"Move":{"start_card":{"Number":{"value":3,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":0,"row":3},"destination":{"column":2,"row":5}}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Green"}},"stack_len":4,"pattern":1,"source":{"column":2,"row":2},"destination":{"column":1,"row":5}}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Red"}},"stack_len":3,"pattern":0,"source":{"column":1,"row":6},"destination":{"column":6,"row":4}}},{"Goal":{"card":{"value":3,"suit":"Black"},"source":{"Field":{"column":6,"row":6}},"goal_slot_index":2}},{"Goal":{"card":{"value":4,"suit":"Black"},"source":{"Field":{"column":4,"row":0}},"goal_slot_index":2}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":4,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":0,"row":2},"to_bunker":true}},{"Goal":{"card":{"value":2,"suit":"Red"},"source":{"Field":{"column":0,"row":1}},"goal_slot_index":0}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":0,"row":0},"destination":{"column":1,"row":6}}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Green"}},"stack_len":2,"pattern":0,"source":{"column":1,"row":5},"destination":{"column":2,"row":2}}},{"Move":{"start_card":{"Number":{"value":4,"suit":"Red"}},"stack_len":2,"pattern":0,"source":{"column":3,"row":3},"destination":{"column":2,"row":4}}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Green"}},"stack_len":4,"pattern":0,"source":{"column":2,"row":2},"destination":{"column":1,"row":5}}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":2,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":2,"field_position":{"column":3,"row":2},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Black"}},"stack_len":3,"pattern":0,"source":{"column":1,"row":6},"destination":{"column":3,"row":2}}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Red"}},"stack_len":4,"pattern":1,"source":{"column":3,"row":1},"destination":{"column":2,"row":2}}},{"Goal":{"card":{"value":3,"suit":"Red"},"source":{"Field":{"column":3,"row":0}},"goal_slot_index":0}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":3,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":1,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":9,"suit":"Red"}},"stack_len":4,"pattern":1,"source":{"column":1,"row":2},"destination":{"column":0,"row":0}}},{"Goal":{"card":{"value":2,"suit":"Green"},"source":{"Field":{"column":1,"row":1}},"goal_slot_index":1}},{"HuaKill":{"field_position":{"column":1,"row":0}}},{"Goal":{"card":{"value":3,"suit":"Green"},"source":{"Field":{"column":2,"row":5}},"goal_slot_index":1}},{"Goal":{"card":{"value":4,"suit":"Red"},"source":{"Field":{"column":2,"row":4}},"goal_slot_index":0}},{"Goal":{"card":{"value":4,"suit":"Green"},"source":{"Field":{"column":6,"row":5}},"goal_slot_index":1}},{"Goal":{"card":{"value":5,"suit":"Black"},"source":{"Field":{"column":2,"row":3}},"goal_slot_index":2}},{"Goal":{"card":{"value":5,"suit":"Red"},"source":{"Field":{"column":6,"row":4}},"goal_slot_index":0}},{"Goal":{"card":{"value":6,"suit":"Red"},"source":{"Field":{"column":2,"row":2}},"goal_slot_index":0}},{"Goal":{"card":{"value":6,"suit":"Black"},"source":{"Field":{"column":6,"row":3}},"goal_slot_index":2}},{"Goal":{"card":{"value":7,"suit":"Black"},"source":{"Field":{"column":2,"row":1}},"goal_slot_index":2}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":1,"field_position":{"column":1,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Green"}},"bunker_slot_index":1,"field_position":{"column":0,"row":3},"to_bunker":true}},{"Goal":{"card":{"value":7,"suit":"Red"},"source":{"Field":{"column":0,"row":2}},"goal_slot_index":0}},{"Goal":{"card":{"value":8,"suit":"Black"},"source":{"Field":{"column":0,"row":1}},"goal_slot_index":2}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":2,"row":0},"destination":{"column":0,"row":1}}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Green"}},"bunker_slot_index":1,"field_position":{"column":2,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":1,"field_position":{"column":1,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Special":"Zhong"},"stack_len":1,"pattern":0,"source":{"column":5,"row":4},"destination":{"column":1,"row":0}}},{"DragonKill":{"card":"Bai","source":[{"Bunker":{"slot_index":1}},{"Bunker":{"slot_index":2}},{"Field":{"column":5,"row":3}},{"Field":{"column":7,"row":0}}],"destination_slot_index":1}},{"Goal":{"card":{"value":5,"suit":"Green"},"source":{"Field":{"column":5,"row":2}},"goal_slot_index":1}},{"Goal":{"card":{"value":6,"suit":"Green"},"source":{"Field":{"column":2,"row":0}},"goal_slot_index":1}},{"Goal":{"card":{"value":7,"suit":"Green"},"source":{"Field":{"column":6,"row":2}},"goal_slot_index":1}},{"Goal":{"card":{"value":8,"suit":"Green"},"source":{"Field":{"column":0,"row":1}},"goal_slot_index":1}},{"Goal":{"card":{"value":8,"suit":"Red"},"source":{"Field":{"column":6,"row":1}},"goal_slot_index":0}},{"Goal":{"card":{"value":9,"suit":"Red"},"source":{"Field":{"column":0,"row":0}},"goal_slot_index":0}},{"Goal":{"card":{"value":9,"suit":"Green"},"source":{"Field":{"column":6,"row":0}},"goal_slot_index":1}},{"DragonKill":{"card":"Zhong","source":[{"Field":{"column":1,"row":0}},{"Field":{"column":3,"row":0}},{"Field":{"column":4,"row":0}},{"Field":{"column":5,"row":1}}],"destination_slot_index":2}},{"Goal":{"card":{"value":9,"suit":"Black"},"source":{"Field":{"column":5,"row":0}},"goal_slot_index":2}}] \ No newline at end of file diff --git a/solver-rs/aux/actions/18.json b/solver-rs/aux/actions/18.json new file mode 100644 index 0000000..676560b --- /dev/null +++ b/solver-rs/aux/actions/18.json @@ -0,0 +1 @@ +[{"Move":{"start_card":{"Number":{"value":3,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":2,"row":4},"destination":{"column":3,"row":5}}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":3,"row":5},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":3,"row":5},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":4,"row":4},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":3,"row":5},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":2,"field_position":{"column":5,"row":4},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":5,"row":4},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":3,"row":5},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":2,"pattern":1,"source":{"column":5,"row":3},"destination":{"column":4,"row":4}}},{"HuaKill":{"field_position":{"column":5,"row":2}}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":3,"row":5},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":4,"row":5},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":3,"row":5},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":5,"row":1},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":4,"row":5},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":2,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":5,"row":0},"destination":{"column":3,"row":6}}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":5,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":3,"row":6},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":4,"row":5},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Green"}},"bunker_slot_index":0,"field_position":{"column":3,"row":6},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":5,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":5,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Green"}},"bunker_slot_index":1,"field_position":{"column":3,"row":6},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":5,"row":0},"destination":{"column":4,"row":5}}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":2,"field_position":{"column":5,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":2,"suit":"Green"}},"bunker_slot_index":1,"field_position":{"column":3,"row":6},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":4,"row":5},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Red"}},"bunker_slot_index":2,"field_position":{"column":6,"row":4},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":4,"row":5},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":1,"field_position":{"column":5,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":5,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":6,"row":3},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":4,"suit":"Green"}},"stack_len":3,"pattern":2,"source":{"column":3,"row":4},"destination":{"column":6,"row":3}}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Red"}},"stack_len":4,"pattern":4,"source":{"column":6,"row":2},"destination":{"column":4,"row":6}}},{"Move":{"start_card":{"Number":{"value":4,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":5,"row":0},"destination":{"column":6,"row":2}}},{"Bunkerize":{"card":{"Number":{"value":6,"suit":"Red"}},"bunker_slot_index":2,"field_position":{"column":5,"row":0},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Green"}},"stack_len":2,"pattern":0,"source":{"column":6,"row":1},"destination":{"column":5,"row":1}}},{"Goal":{"card":{"value":1,"suit":"Green"},"source":{"Field":{"column":6,"row":0}},"goal_slot_index":0}},{"Goal":{"card":{"value":2,"suit":"Green"},"source":{"Field":{"column":4,"row":9}},"goal_slot_index":0}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":6,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":4,"row":8},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Black"}},"bunker_slot_index":2,"field_position":{"column":5,"row":2},"to_bunker":true}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Black"}},"bunker_slot_index":0,"field_position":{"column":4,"row":8},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":6,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":1,"field_position":{"column":6,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Black"}},"bunker_slot_index":2,"field_position":{"column":5,"row":2},"to_bunker":false}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":4,"row":8},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":2,"field_position":{"column":6,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":9,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":7,"row":4},"destination":{"column":6,"row":0}}},{"Bunkerize":{"card":{"Number":{"value":3,"suit":"Black"}},"bunker_slot_index":1,"field_position":{"column":4,"row":8},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":7,"row":3},"destination":{"column":1,"row":5}}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":1,"field_position":{"column":7,"row":2},"to_bunker":true}},{"Goal":{"card":{"value":1,"suit":"Black"},"source":{"Field":{"column":7,"row":1}},"goal_slot_index":1}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":5,"pattern":1,"source":{"column":4,"row":4},"destination":{"column":7,"row":1}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Green"}},"stack_len":6,"pattern":3,"source":{"column":7,"row":0},"destination":{"column":6,"row":1}}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":7,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":0,"field_position":{"column":3,"row":3},"to_bunker":true}},{"Goal":{"card":{"value":2,"suit":"Black"},"source":{"Field":{"column":3,"row":2}},"goal_slot_index":1}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Black"}},"stack_len":1,"pattern":0,"source":{"column":3,"row":1},"destination":{"column":1,"row":6}}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Red"}},"stack_len":3,"pattern":0,"source":{"column":5,"row":0},"destination":{"column":1,"row":7}}},{"Bunkerize":{"card":{"Special":"Bai"},"bunker_slot_index":0,"field_position":{"column":5,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":2,"row":3},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":2,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":2,"row":2},"destination":{"column":6,"row":7}}},{"DragonKill":{"card":"Bai","source":[{"Bunker":{"slot_index":2}},{"Field":{"column":2,"row":1}},{"Field":{"column":3,"row":0}},{"Field":{"column":5,"row":0}}],"destination_slot_index":2}},{"Goal":{"card":{"value":1,"suit":"Red"},"source":{"Field":{"column":2,"row":0}},"goal_slot_index":2}},{"Goal":{"card":{"value":2,"suit":"Red"},"source":{"Field":{"column":6,"row":7}},"goal_slot_index":2}},{"Goal":{"card":{"value":3,"suit":"Black"},"source":{"Field":{"column":6,"row":6}},"goal_slot_index":1}},{"Goal":{"card":{"value":4,"suit":"Black"},"source":{"Field":{"column":1,"row":9}},"goal_slot_index":1}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":2,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":1,"field_position":{"column":3,"row":0},"to_bunker":false}},{"Move":{"start_card":{"Special":"Zhong"},"stack_len":1,"pattern":0,"source":{"column":0,"row":4},"destination":{"column":5,"row":0}}},{"Move":{"start_card":{"Number":{"value":4,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":0,"row":3},"destination":{"column":1,"row":9}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":4,"pattern":1,"source":{"column":6,"row":2},"destination":{"column":4,"row":4}}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Black"}},"stack_len":4,"pattern":4,"source":{"column":1,"row":6},"destination":{"column":6,"row":2}}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":0,"row":2},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Green"}},"stack_len":1,"pattern":0,"source":{"column":0,"row":1},"destination":{"column":1,"row":6}}},{"Goal":{"card":{"value":5,"suit":"Black"},"source":{"Field":{"column":0,"row":0}},"goal_slot_index":1}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":false}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Black"}},"stack_len":3,"pattern":0,"source":{"column":4,"row":5},"destination":{"column":1,"row":7}}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":0,"row":0},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":9,"suit":"Green"}},"stack_len":6,"pattern":1,"source":{"column":1,"row":4},"destination":{"column":0,"row":0}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Red"}},"stack_len":5,"pattern":0,"source":{"column":0,"row":1},"destination":{"column":1,"row":4}}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Black"}},"stack_len":2,"pattern":0,"source":{"column":4,"row":3},"destination":{"column":0,"row":1}}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Green"}},"bunker_slot_index":1,"field_position":{"column":1,"row":8},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Black"}},"stack_len":2,"pattern":0,"source":{"column":1,"row":6},"destination":{"column":0,"row":3}}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Red"}},"stack_len":3,"pattern":2,"source":{"column":6,"row":3},"destination":{"column":1,"row":6}}},{"Bunkerize":{"card":{"Number":{"value":4,"suit":"Green"}},"bunker_slot_index":1,"field_position":{"column":0,"row":5},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":1,"field_position":{"column":2,"row":0},"to_bunker":true}},{"Bunkerize":{"card":{"Special":"Fa"},"bunker_slot_index":0,"field_position":{"column":2,"row":0},"to_bunker":false}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":4,"row":2},"to_bunker":true}},{"Move":{"start_card":{"Number":{"value":5,"suit":"Red"}},"stack_len":2,"pattern":0,"source":{"column":0,"row":4},"destination":{"column":4,"row":2}}},{"Goal":{"card":{"value":6,"suit":"Black"},"source":{"Field":{"column":0,"row":3}},"goal_slot_index":1}},{"Goal":{"card":{"value":7,"suit":"Black"},"source":{"Field":{"column":6,"row":2}},"goal_slot_index":1}},{"Move":{"start_card":{"Number":{"value":7,"suit":"Red"}},"stack_len":1,"pattern":0,"source":{"column":0,"row":2},"destination":{"column":6,"row":2}}},{"Goal":{"card":{"value":8,"suit":"Black"},"source":{"Field":{"column":0,"row":1}},"goal_slot_index":1}},{"Move":{"start_card":{"Number":{"value":8,"suit":"Red"}},"stack_len":5,"pattern":10,"source":{"column":1,"row":4},"destination":{"column":0,"row":1}}},{"Goal":{"card":{"value":9,"suit":"Black"},"source":{"Field":{"column":1,"row":3}},"goal_slot_index":1}},{"Move":{"start_card":{"Number":{"value":6,"suit":"Green"}},"stack_len":3,"pattern":1,"source":{"column":4,"row":1},"destination":{"column":6,"row":3}}},{"Goal":{"card":{"value":3,"suit":"Green"},"source":{"Field":{"column":4,"row":0}},"goal_slot_index":0}},{"Goal":{"card":{"value":4,"suit":"Green"},"source":{"Field":{"column":6,"row":5}},"goal_slot_index":0}},{"Bunkerize":{"card":{"Special":"Zhong"},"bunker_slot_index":0,"field_position":{"column":4,"row":0},"to_bunker":false}},{"DragonKill":{"card":"Fa","source":[{"Field":{"column":1,"row":2}},{"Field":{"column":2,"row":0}},{"Field":{"column":3,"row":0}},{"Field":{"column":7,"row":0}}],"destination_slot_index":0}},{"Goal":{"card":{"value":3,"suit":"Red"},"source":{"Field":{"column":1,"row":1}},"goal_slot_index":2}},{"Goal":{"card":{"value":4,"suit":"Red"},"source":{"Field":{"column":0,"row":5}},"goal_slot_index":2}},{"Goal":{"card":{"value":5,"suit":"Green"},"source":{"Field":{"column":0,"row":4}},"goal_slot_index":0}},{"Goal":{"card":{"value":5,"suit":"Red"},"source":{"Field":{"column":6,"row":4}},"goal_slot_index":2}},{"Goal":{"card":{"value":6,"suit":"Red"},"source":{"Field":{"column":0,"row":3}},"goal_slot_index":2}},{"Goal":{"card":{"value":6,"suit":"Green"},"source":{"Field":{"column":6,"row":3}},"goal_slot_index":0}},{"Goal":{"card":{"value":7,"suit":"Green"},"source":{"Field":{"column":0,"row":2}},"goal_slot_index":0}},{"Goal":{"card":{"value":7,"suit":"Red"},"source":{"Field":{"column":6,"row":2}},"goal_slot_index":2}},{"Goal":{"card":{"value":8,"suit":"Red"},"source":{"Field":{"column":0,"row":1}},"goal_slot_index":2}},{"Goal":{"card":{"value":8,"suit":"Green"},"source":{"Field":{"column":6,"row":1}},"goal_slot_index":0}},{"Goal":{"card":{"value":9,"suit":"Green"},"source":{"Field":{"column":0,"row":0}},"goal_slot_index":0}},{"Goal":{"card":{"value":9,"suit":"Red"},"source":{"Field":{"column":6,"row":0}},"goal_slot_index":2}},{"DragonKill":{"card":"Zhong","source":[{"Bunker":{"slot_index":1}},{"Field":{"column":1,"row":0}},{"Field":{"column":4,"row":0}},{"Field":{"column":5,"row":0}}],"destination_slot_index":1}}] \ No newline at end of file diff --git a/solver-rs/aux/boards/normal/01.json b/solver-rs/aux/boards/normal/01.json new file mode 100644 index 0000000..3cdf490 --- /dev/null +++ b/solver-rs/aux/boards/normal/01.json @@ -0,0 +1 @@ +{"field": [[{"Number": {"value": 3, "suit": "Green"}}, {"Special": "Fa"}, {"Number": {"value": 1, "suit": "Green"}}, {"Special": "Fa"}, {"Special": "Zhong"}], [{"Number": {"value": 2, "suit": "Green"}}, {"Number": {"value": 1, "suit": "Black"}}, {"Number": {"value": 6, "suit": "Green"}}, {"Number": {"value": 5, "suit": "Green"}}, {"Special": "Zhong"}], [{"Special": "Zhong"}, {"Special": "Bai"}, {"Number": {"value": 6, "suit": "Red"}}, {"Number": {"value": 3, "suit": "Red"}}, {"Number": {"value": 5, "suit": "Black"}}], [{"Special": "Fa"}, {"Number": {"value": 4, "suit": "Red"}}, {"Number": {"value": 9, "suit": "Black"}}, {"Number": {"value": 5, "suit": "Red"}}, {"Number": {"value": 4, "suit": "Black"}}], [{"Number": {"value": 7, "suit": "Black"}}, {"Special": "Zhong"}, {"Number": {"value": 9, "suit": "Green"}}, {"Number": {"value": 7, "suit": "Red"}}, {"Number": {"value": 6, "suit": "Black"}}], [{"Number": {"value": 2, "suit": "Red"}}, {"Special": "Bai"}, {"Number": {"value": 3, "suit": "Black"}}, {"Special": "Bai"}, {"Number": {"value": 8, "suit": "Black"}}], [{"Number": {"value": 4, "suit": "Green"}}, "Hua", {"Number": {"value": 7, "suit": "Green"}}, {"Special": "Fa"}, {"Number": {"value": 9, "suit": "Red"}}], [{"Number": {"value": 8, "suit": "Red"}}, {"Special": "Bai"}, {"Number": {"value": 2, "suit": "Black"}}, {"Number": {"value": 1, "suit": "Red"}}, {"Number": {"value": 8, "suit": "Green"}}]], "hua_set": false, "bunker": ["Empty", "Empty", "Empty"], "goal": [null, null, null]} diff --git a/solver-rs/aux/boards/normal/02.json b/solver-rs/aux/boards/normal/02.json new file mode 100644 index 0000000..dbb2ba1 --- /dev/null +++ b/solver-rs/aux/boards/normal/02.json @@ -0,0 +1 @@ +{"field": [[{"Number": {"value": 8, "suit": "Red"}}, {"Special": "Fa"}, {"Number": {"value": 3, "suit": "Green"}}, "Hua", {"Number": {"value": 8, "suit": "Green"}}], [{"Special": "Bai"}, {"Number": {"value": 1, "suit": "Green"}}, {"Special": "Bai"}, {"Special": "Zhong"}, {"Number": {"value": 2, "suit": "Green"}}], [{"Special": "Fa"}, {"Number": {"value": 6, "suit": "Red"}}, {"Number": {"value": 5, "suit": "Green"}}, {"Number": {"value": 6, "suit": "Green"}}, {"Number": {"value": 4, "suit": "Green"}}], [{"Number": {"value": 1, "suit": "Black"}}, {"Number": {"value": 7, "suit": "Black"}}, {"Number": {"value": 5, "suit": "Black"}}, {"Number": {"value": 7, "suit": "Red"}}, {"Special": "Zhong"}], [{"Special": "Bai"}, {"Number": {"value": 1, "suit": "Red"}}, {"Special": "Fa"}, {"Number": {"value": 6, "suit": "Black"}}, {"Number": {"value": 2, "suit": "Red"}}], [{"Number": {"value": 5, "suit": "Red"}}, {"Special": "Fa"}, {"Number": {"value": 8, "suit": "Black"}}, {"Number": {"value": 3, "suit": "Black"}}, {"Special": "Zhong"}], [{"Number": {"value": 4, "suit": "Red"}}, {"Number": {"value": 4, "suit": "Black"}}, {"Number": {"value": 9, "suit": "Red"}}, {"Special": "Bai"}, {"Number": {"value": 3, "suit": "Red"}}], [{"Number": {"value": 9, "suit": "Black"}}, {"Number": {"value": 9, "suit": "Green"}}, {"Number": {"value": 7, "suit": "Green"}}, {"Number": {"value": 2, "suit": "Black"}}, {"Special": "Zhong"}]], "hua_set": false, "bunker": ["Empty", "Empty", "Empty"], "goal": [null, null, null]} diff --git a/solver-rs/aux/boards/normal/03.json b/solver-rs/aux/boards/normal/03.json new file mode 100644 index 0000000..d6560f5 --- /dev/null +++ b/solver-rs/aux/boards/normal/03.json @@ -0,0 +1 @@ +{"field": [[{"Number": {"value": 4, "suit": "Green"}}, {"Number": {"value": 1, "suit": "Red"}}, {"Special": "Fa"}, {"Number": {"value": 5, "suit": "Black"}}, {"Number": {"value": 8, "suit": "Green"}}], [{"Number": {"value": 2, "suit": "Black"}}, {"Number": {"value": 3, "suit": "Green"}}, {"Number": {"value": 9, "suit": "Red"}}, {"Number": {"value": 7, "suit": "Red"}}, {"Number": {"value": 2, "suit": "Red"}}], [{"Number": {"value": 1, "suit": "Green"}}, {"Number": {"value": 1, "suit": "Black"}}, {"Special": "Fa"}, {"Number": {"value": 6, "suit": "Black"}}, {"Special": "Zhong"}], [{"Special": "Fa"}, {"Number": {"value": 5, "suit": "Green"}}, {"Number": {"value": 5, "suit": "Red"}}, {"Special": "Zhong"}, {"Special": "Zhong"}], [{"Number": {"value": 8, "suit": "Red"}}, {"Number": {"value": 6, "suit": "Green"}}, {"Number": {"value": 3, "suit": "Red"}}, {"Special": "Bai"}, {"Number": {"value": 2, "suit": "Green"}}], [{"Number": {"value": 9, "suit": "Green"}}, "Hua", {"Number": {"value": 9, "suit": "Black"}}, {"Number": {"value": 8, "suit": "Black"}}, {"Special": "Fa"}], [{"Number": {"value": 3, "suit": "Black"}}, {"Special": "Zhong"}, {"Number": {"value": 4, "suit": "Red"}}, {"Special": "Bai"}, {"Number": {"value": 7, "suit": "Black"}}], [{"Number": {"value": 7, "suit": "Green"}}, {"Special": "Bai"}, {"Number": {"value": 4, "suit": "Black"}}, {"Number": {"value": 6, "suit": "Red"}}, {"Special": "Bai"}]], "hua_set": false, "bunker": ["Empty", "Empty", "Empty"], "goal": [null, null, null]} diff --git a/solver-rs/aux/boards/normal/04.json b/solver-rs/aux/boards/normal/04.json new file mode 100644 index 0000000..c6bede3 --- /dev/null +++ b/solver-rs/aux/boards/normal/04.json @@ -0,0 +1 @@ +{"field": [[{"Special": "Bai"}, {"Number": {"value": 5, "suit": "Green"}}, {"Number": {"value": 7, "suit": "Red"}}, {"Number": {"value": 7, "suit": "Green"}}, {"Special": "Bai"}], [{"Number": {"value": 9, "suit": "Red"}}, {"Special": "Bai"}, {"Number": {"value": 4, "suit": "Black"}}], [{"Number": {"value": 7, "suit": "Black"}}, {"Special": "Bai"}, {"Number": {"value": 1, "suit": "Green"}}, {"Number": {"value": 4, "suit": "Red"}}, {"Special": "Zhong"}], [{"Special": "Fa"}, {"Number": {"value": 6, "suit": "Red"}}, {"Special": "Zhong"}, {"Special": "Fa"}, {"Number": {"value": 4, "suit": "Green"}}], [{"Number": {"value": 3, "suit": "Black"}}, {"Number": {"value": 9, "suit": "Black"}}, {"Special": "Fa"}, {"Special": "Zhong"}, {"Number": {"value": 5, "suit": "Black"}}], [{"Number": {"value": 3, "suit": "Green"}}, {"Number": {"value": 2, "suit": "Green"}}, {"Number": {"value": 2, "suit": "Red"}}, {"Number": {"value": 6, "suit": "Green"}}, {"Special": "Zhong"}], [{"Number": {"value": 6, "suit": "Black"}}, {"Number": {"value": 5, "suit": "Red"}}, {"Number": {"value": 2, "suit": "Black"}}, {"Number": {"value": 9, "suit": "Green"}}, {"Number": {"value": 8, "suit": "Green"}}], ["Hua", {"Special": "Fa"}, {"Number": {"value": 8, "suit": "Red"}}, {"Number": {"value": 8, "suit": "Black"}}, {"Number": {"value": 3, "suit": "Red"}}]], "hua_set": false, "bunker": ["Empty", "Empty", "Empty"], "goal": [{"value": 1, "suit": "Red"}, {"value": 1, "suit": "Black"}, null]} diff --git a/solver-rs/aux/boards/normal/05.json b/solver-rs/aux/boards/normal/05.json new file mode 100644 index 0000000..15c1077 --- /dev/null +++ b/solver-rs/aux/boards/normal/05.json @@ -0,0 +1 @@ +{"field": [[{"Special": "Fa"}, {"Number": {"value": 8, "suit": "Red"}}, {"Special": "Zhong"}, {"Special": "Bai"}, {"Number": {"value": 4, "suit": "Green"}}], [{"Number": {"value": 9, "suit": "Black"}}, {"Number": {"value": 6, "suit": "Black"}}, {"Number": {"value": 7, "suit": "Red"}}, {"Number": {"value": 7, "suit": "Black"}}], [{"Number": {"value": 3, "suit": "Green"}}, {"Special": "Zhong"}, {"Special": "Fa"}, {"Special": "Bai"}], [{"Number": {"value": 3, "suit": "Red"}}, {"Number": {"value": 9, "suit": "Green"}}, {"Number": {"value": 8, "suit": "Green"}}, {"Number": {"value": 8, "suit": "Black"}}, {"Number": {"value": 2, "suit": "Green"}}], [{"Special": "Bai"}, {"Number": {"value": 6, "suit": "Green"}}, {"Number": {"value": 1, "suit": "Green"}}, {"Number": {"value": 2, "suit": "Black"}}, {"Special": "Fa"}], [{"Number": {"value": 6, "suit": "Red"}}, {"Special": "Fa"}, {"Number": {"value": 2, "suit": "Red"}}, {"Special": "Zhong"}, {"Number": {"value": 9, "suit": "Red"}}], [{"Number": {"value": 7, "suit": "Green"}}, {"Number": {"value": 4, "suit": "Black"}}, {"Number": {"value": 5, "suit": "Green"}}, {"Number": {"value": 5, "suit": "Black"}}, {"Number": {"value": 4, "suit": "Red"}}], [{"Special": "Zhong"}, {"Number": {"value": 1, "suit": "Red"}}, {"Special": "Bai"}, {"Number": {"value": 3, "suit": "Black"}}, {"Number": {"value": 5, "suit": "Red"}}]], "hua_set": true, "bunker": ["Empty", "Empty", "Empty"], "goal": [{"value": 1, "suit": "Black"}, null, null]} diff --git a/solver-rs/aux/boards/normal/06.json b/solver-rs/aux/boards/normal/06.json new file mode 100644 index 0000000..8e41afa --- /dev/null +++ b/solver-rs/aux/boards/normal/06.json @@ -0,0 +1 @@ +{"field": [[{"Number": {"value": 2, "suit": "Black"}}, {"Number": {"value": 1, "suit": "Red"}}, {"Number": {"value": 2, "suit": "Green"}}, {"Number": {"value": 8, "suit": "Green"}}, {"Number": {"value": 9, "suit": "Green"}}], [{"Number": {"value": 5, "suit": "Red"}}, {"Number": {"value": 5, "suit": "Black"}}, {"Number": {"value": 9, "suit": "Black"}}, {"Number": {"value": 1, "suit": "Black"}}, {"Number": {"value": 9, "suit": "Red"}}], [{"Number": {"value": 8, "suit": "Black"}}, {"Number": {"value": 8, "suit": "Red"}}, {"Special": "Zhong"}, {"Number": {"value": 3, "suit": "Green"}}], [{"Number": {"value": 7, "suit": "Red"}}, {"Number": {"value": 6, "suit": "Red"}}, {"Number": {"value": 4, "suit": "Red"}}, {"Special": "Zhong"}, {"Number": {"value": 2, "suit": "Red"}}], [{"Number": {"value": 7, "suit": "Green"}}, {"Special": "Bai"}, {"Special": "Zhong"}, {"Special": "Fa"}, {"Special": "Bai"}], [{"Number": {"value": 6, "suit": "Green"}}, {"Number": {"value": 3, "suit": "Red"}}, {"Number": {"value": 6, "suit": "Black"}}, {"Special": "Bai"}, {"Number": {"value": 5, "suit": "Green"}}], [{"Special": "Fa"}, "Hua", {"Number": {"value": 3, "suit": "Black"}}, {"Special": "Bai"}, {"Number": {"value": 4, "suit": "Black"}}], [{"Special": "Fa"}, {"Special": "Fa"}, {"Special": "Zhong"}, {"Number": {"value": 4, "suit": "Green"}}, {"Number": {"value": 7, "suit": "Black"}}]], "hua_set": false, "bunker": ["Empty", "Empty", "Empty"], "goal": [{"value": 1, "suit": "Green"}, null, null]} diff --git a/solver-rs/aux/boards/normal/07.json b/solver-rs/aux/boards/normal/07.json new file mode 100644 index 0000000..b64fd2c --- /dev/null +++ b/solver-rs/aux/boards/normal/07.json @@ -0,0 +1 @@ +{"field": [[{"Number": {"value": 7, "suit": "Green"}}, {"Number": {"value": 1, "suit": "Red"}}, {"Number": {"value": 2, "suit": "Red"}}, {"Number": {"value": 1, "suit": "Green"}}, {"Special": "Bai"}], [{"Number": {"value": 9, "suit": "Red"}}, {"Number": {"value": 1, "suit": "Black"}}, {"Special": "Zhong"}, {"Number": {"value": 3, "suit": "Black"}}, {"Special": "Fa"}], [{"Number": {"value": 8, "suit": "Green"}}, {"Number": {"value": 6, "suit": "Red"}}, {"Number": {"value": 2, "suit": "Green"}}, {"Number": {"value": 4, "suit": "Red"}}, {"Number": {"value": 8, "suit": "Black"}}], [{"Number": {"value": 9, "suit": "Green"}}, {"Number": {"value": 5, "suit": "Green"}}, {"Special": "Fa"}, {"Special": "Bai"}, {"Number": {"value": 7, "suit": "Black"}}], ["Hua", {"Number": {"value": 5, "suit": "Black"}}, {"Number": {"value": 9, "suit": "Black"}}, {"Special": "Fa"}, {"Number": {"value": 8, "suit": "Red"}}], [{"Special": "Zhong"}, {"Special": "Zhong"}, {"Number": {"value": 2, "suit": "Black"}}, {"Number": {"value": 3, "suit": "Green"}}, {"Number": {"value": 5, "suit": "Red"}}], [{"Number": {"value": 6, "suit": "Black"}}, {"Number": {"value": 4, "suit": "Green"}}, {"Number": {"value": 7, "suit": "Red"}}, {"Special": "Fa"}, {"Number": {"value": 3, "suit": "Red"}}], [{"Special": "Bai"}, {"Special": "Zhong"}, {"Number": {"value": 6, "suit": "Green"}}, {"Special": "Bai"}, {"Number": {"value": 4, "suit": "Black"}}]], "hua_set": false, "bunker": ["Empty", "Empty", "Empty"], "goal": [null, null, null]} diff --git a/solver-rs/aux/boards/normal/08.json b/solver-rs/aux/boards/normal/08.json new file mode 100644 index 0000000..bfea4cd --- /dev/null +++ b/solver-rs/aux/boards/normal/08.json @@ -0,0 +1 @@ +{"field": [[{"Number": {"value": 2, "suit": "Red"}}, {"Number": {"value": 9, "suit": "Red"}}, {"Number": {"value": 5, "suit": "Green"}}, {"Special": "Bai"}, {"Number": {"value": 7, "suit": "Black"}}], [{"Special": "Zhong"}, {"Number": {"value": 4, "suit": "Black"}}, {"Number": {"value": 4, "suit": "Green"}}, "Hua", {"Number": {"value": 8, "suit": "Red"}}], [{"Number": {"value": 6, "suit": "Black"}}, {"Number": {"value": 8, "suit": "Black"}}, {"Special": "Bai"}, {"Special": "Fa"}], [{"Number": {"value": 3, "suit": "Black"}}, {"Number": {"value": 3, "suit": "Green"}}, {"Number": {"value": 3, "suit": "Red"}}, {"Special": "Bai"}, {"Number": {"value": 4, "suit": "Red"}}], [{"Special": "Zhong"}, {"Special": "Fa"}, {"Number": {"value": 1, "suit": "Black"}}, {"Special": "Zhong"}, {"Number": {"value": 8, "suit": "Green"}}], [{"Number": {"value": 7, "suit": "Red"}}, {"Number": {"value": 9, "suit": "Green"}}, {"Number": {"value": 7, "suit": "Green"}}, {"Number": {"value": 5, "suit": "Red"}}], [{"Special": "Bai"}, {"Number": {"value": 5, "suit": "Black"}}, {"Number": {"value": 6, "suit": "Green"}}, {"Special": "Zhong"}, {"Number": {"value": 9, "suit": "Black"}}], [{"Number": {"value": 1, "suit": "Red"}}, {"Special": "Fa"}, {"Special": "Fa"}, {"Number": {"value": 6, "suit": "Red"}}, {"Number": {"value": 2, "suit": "Black"}}]], "hua_set": false, "bunker": ["Empty", "Empty", "Empty"], "goal": [{"value": 2, "suit": "Green"}, null, null]} diff --git a/solver-rs/aux/boards/normal/09.json b/solver-rs/aux/boards/normal/09.json new file mode 100644 index 0000000..8963920 --- /dev/null +++ b/solver-rs/aux/boards/normal/09.json @@ -0,0 +1 @@ +{"field": [[{"Number": {"value": 7, "suit": "Green"}}, {"Special": "Zhong"}, {"Number": {"value": 2, "suit": "Red"}}, {"Number": {"value": 6, "suit": "Red"}}, {"Number": {"value": 4, "suit": "Black"}}], [{"Special": "Bai"}, {"Number": {"value": 4, "suit": "Green"}}, {"Special": "Bai"}, {"Number": {"value": 3, "suit": "Black"}}], [{"Number": {"value": 9, "suit": "Red"}}, {"Number": {"value": 7, "suit": "Black"}}, {"Special": "Fa"}, {"Special": "Zhong"}, {"Number": {"value": 3, "suit": "Green"}}], [{"Number": {"value": 2, "suit": "Green"}}, {"Special": "Zhong"}, {"Number": {"value": 1, "suit": "Black"}}, {"Number": {"value": 4, "suit": "Red"}}, {"Number": {"value": 8, "suit": "Red"}}], [{"Number": {"value": 2, "suit": "Black"}}, {"Special": "Fa"}, {"Number": {"value": 8, "suit": "Green"}}, {"Number": {"value": 3, "suit": "Red"}}, {"Number": {"value": 7, "suit": "Red"}}], [{"Number": {"value": 5, "suit": "Black"}}, {"Special": "Fa"}, {"Number": {"value": 1, "suit": "Green"}}, {"Special": "Zhong"}, {"Special": "Fa"}], [{"Special": "Bai"}, {"Number": {"value": 9, "suit": "Black"}}, {"Number": {"value": 8, "suit": "Black"}}, {"Special": "Bai"}], [{"Number": {"value": 5, "suit": "Green"}}, {"Number": {"value": 9, "suit": "Green"}}, {"Number": {"value": 6, "suit": "Black"}}, {"Number": {"value": 6, "suit": "Green"}}, {"Number": {"value": 5, "suit": "Red"}}]], "hua_set": true, "bunker": ["Empty", "Empty", "Empty"], "goal": [{"value": 1, "suit": "Red"}, null, null]} diff --git a/solver-rs/aux/boards/normal/10.json b/solver-rs/aux/boards/normal/10.json new file mode 100644 index 0000000..01bb184 --- /dev/null +++ b/solver-rs/aux/boards/normal/10.json @@ -0,0 +1 @@ +{"field": [[{"Special": "Fa"}, {"Number": {"value": 3, "suit": "Green"}}, {"Number": {"value": 5, "suit": "Red"}}, {"Special": "Zhong"}, {"Special": "Fa"}], [{"Number": {"value": 1, "suit": "Red"}}, {"Special": "Bai"}, {"Number": {"value": 7, "suit": "Red"}}, {"Number": {"value": 9, "suit": "Green"}}, {"Number": {"value": 7, "suit": "Black"}}], [{"Number": {"value": 4, "suit": "Black"}}, {"Number": {"value": 9, "suit": "Black"}}, {"Number": {"value": 2, "suit": "Green"}}, {"Special": "Zhong"}, {"Number": {"value": 8, "suit": "Black"}}], [{"Special": "Zhong"}, {"Special": "Zhong"}, {"Number": {"value": 4, "suit": "Green"}}, {"Special": "Bai"}], [{"Number": {"value": 2, "suit": "Red"}}, {"Number": {"value": 2, "suit": "Black"}}, {"Number": {"value": 6, "suit": "Black"}}, {"Number": {"value": 6, "suit": "Red"}}, {"Number": {"value": 4, "suit": "Red"}}], [{"Special": "Fa"}, {"Number": {"value": 6, "suit": "Green"}}, {"Number": {"value": 3, "suit": "Red"}}, "Hua", {"Number": {"value": 5, "suit": "Green"}}], [{"Special": "Fa"}, {"Special": "Bai"}, {"Number": {"value": 8, "suit": "Green"}}, {"Number": {"value": 3, "suit": "Black"}}, {"Number": {"value": 5, "suit": "Black"}}], [{"Special": "Bai"}, {"Number": {"value": 9, "suit": "Red"}}, {"Number": {"value": 8, "suit": "Red"}}, {"Number": {"value": 1, "suit": "Green"}}, {"Number": {"value": 7, "suit": "Green"}}]], "hua_set": false, "bunker": ["Empty", "Empty", "Empty"], "goal": [{"value": 1, "suit": "Black"}, null, null]} diff --git a/solver-rs/aux/boards/normal/11.json b/solver-rs/aux/boards/normal/11.json new file mode 100644 index 0000000..0396c4a --- /dev/null +++ b/solver-rs/aux/boards/normal/11.json @@ -0,0 +1 @@ +{"field": [[{"Number": {"value": 6, "suit": "Black"}}, {"Number": {"value": 8, "suit": "Green"}}, {"Special": "Fa"}, {"Number": {"value": 5, "suit": "Red"}}, {"Number": {"value": 6, "suit": "Red"}}], [{"Special": "Bai"}, "Hua", {"Special": "Bai"}, {"Number": {"value": 2, "suit": "Red"}}, {"Number": {"value": 7, "suit": "Green"}}], [{"Number": {"value": 1, "suit": "Green"}}, {"Special": "Fa"}, {"Number": {"value": 5, "suit": "Black"}}, {"Special": "Bai"}, {"Number": {"value": 9, "suit": "Red"}}], [{"Number": {"value": 1, "suit": "Red"}}, {"Number": {"value": 5, "suit": "Green"}}, {"Number": {"value": 6, "suit": "Green"}}, {"Number": {"value": 3, "suit": "Black"}}, {"Number": {"value": 3, "suit": "Green"}}], [{"Special": "Bai"}, {"Number": {"value": 7, "suit": "Red"}}, {"Number": {"value": 4, "suit": "Red"}}, {"Number": {"value": 9, "suit": "Green"}}, {"Number": {"value": 9, "suit": "Black"}}], [{"Number": {"value": 2, "suit": "Green"}}, {"Number": {"value": 1, "suit": "Black"}}, {"Number": {"value": 4, "suit": "Green"}}, {"Special": "Fa"}, {"Number": {"value": 7, "suit": "Black"}}], [{"Number": {"value": 2, "suit": "Black"}}, {"Special": "Fa"}, {"Number": {"value": 8, "suit": "Red"}}, {"Number": {"value": 4, "suit": "Black"}}, {"Special": "Zhong"}], [{"Special": "Zhong"}, {"Number": {"value": 8, "suit": "Black"}}, {"Number": {"value": 3, "suit": "Red"}}, {"Special": "Zhong"}, {"Special": "Zhong"}]], "hua_set": false, "bunker": ["Empty", "Empty", "Empty"], "goal": [null, null, null]} diff --git a/solver-rs/aux/boards/normal/12.json b/solver-rs/aux/boards/normal/12.json new file mode 100644 index 0000000..123706d --- /dev/null +++ b/solver-rs/aux/boards/normal/12.json @@ -0,0 +1 @@ +{"field": [[{"Number": {"value": 5, "suit": "Red"}}, {"Number": {"value": 7, "suit": "Red"}}, {"Number": {"value": 9, "suit": "Green"}}, "Hua", {"Number": {"value": 3, "suit": "Black"}}], [{"Number": {"value": 2, "suit": "Black"}}, {"Number": {"value": 4, "suit": "Black"}}, {"Number": {"value": 9, "suit": "Black"}}, {"Number": {"value": 4, "suit": "Green"}}, {"Special": "Bai"}], [{"Number": {"value": 8, "suit": "Green"}}, {"Number": {"value": 3, "suit": "Green"}}, {"Number": {"value": 3, "suit": "Red"}}, {"Number": {"value": 1, "suit": "Green"}}, {"Number": {"value": 7, "suit": "Black"}}], [{"Special": "Bai"}, {"Number": {"value": 1, "suit": "Red"}}, {"Number": {"value": 5, "suit": "Black"}}, {"Special": "Bai"}, {"Number": {"value": 2, "suit": "Green"}}], [{"Special": "Fa"}, {"Special": "Fa"}, {"Special": "Fa"}, {"Number": {"value": 6, "suit": "Green"}}, {"Number": {"value": 6, "suit": "Red"}}], [{"Special": "Zhong"}, {"Number": {"value": 4, "suit": "Red"}}, {"Number": {"value": 8, "suit": "Black"}}, {"Special": "Zhong"}, {"Number": {"value": 9, "suit": "Red"}}], [{"Number": {"value": 2, "suit": "Red"}}, {"Special": "Zhong"}, {"Number": {"value": 6, "suit": "Black"}}, {"Number": {"value": 5, "suit": "Green"}}, {"Special": "Fa"}], [{"Special": "Bai"}, {"Special": "Zhong"}, {"Number": {"value": 7, "suit": "Green"}}, {"Number": {"value": 8, "suit": "Red"}}]], "hua_set": false, "bunker": ["Empty", "Empty", "Empty"], "goal": [{"value": 1, "suit": "Black"}, null, null]} diff --git a/solver-rs/aux/boards/normal/13.json b/solver-rs/aux/boards/normal/13.json new file mode 100644 index 0000000..882e7fa --- /dev/null +++ b/solver-rs/aux/boards/normal/13.json @@ -0,0 +1 @@ +{"field": [[{"Special": "Fa"}, {"Number": {"value": 3, "suit": "Black"}}, {"Number": {"value": 4, "suit": "Black"}}, {"Number": {"value": 9, "suit": "Red"}}, {"Number": {"value": 7, "suit": "Red"}}], [{"Number": {"value": 5, "suit": "Black"}}, {"Number": {"value": 7, "suit": "Black"}}, {"Number": {"value": 2, "suit": "Black"}}, {"Number": {"value": 1, "suit": "Black"}}, {"Special": "Bai"}], [{"Number": {"value": 9, "suit": "Green"}}, {"Number": {"value": 1, "suit": "Green"}}, {"Special": "Bai"}, {"Special": "Bai"}, {"Special": "Fa"}], [{"Special": "Fa"}, {"Number": {"value": 2, "suit": "Green"}}, {"Number": {"value": 2, "suit": "Red"}}, {"Number": {"value": 8, "suit": "Black"}}, {"Number": {"value": 8, "suit": "Red"}}], [{"Special": "Zhong"}, {"Special": "Zhong"}, {"Number": {"value": 5, "suit": "Green"}}, {"Number": {"value": 6, "suit": "Red"}}, {"Number": {"value": 3, "suit": "Green"}}], [{"Number": {"value": 9, "suit": "Black"}}, {"Number": {"value": 6, "suit": "Green"}}, {"Number": {"value": 6, "suit": "Black"}}, {"Special": "Zhong"}, {"Number": {"value": 7, "suit": "Green"}}], [{"Number": {"value": 1, "suit": "Red"}}, {"Number": {"value": 3, "suit": "Red"}}, {"Number": {"value": 4, "suit": "Green"}}, {"Number": {"value": 4, "suit": "Red"}}], [{"Special": "Bai"}, {"Special": "Fa"}, {"Number": {"value": 5, "suit": "Red"}}, {"Number": {"value": 8, "suit": "Green"}}, {"Special": "Zhong"}]], "hua_set": true, "bunker": ["Empty", "Empty", "Empty"], "goal": [null, null, null]} diff --git a/solver-rs/aux/boards/normal/14.json b/solver-rs/aux/boards/normal/14.json new file mode 100644 index 0000000..cf16fa6 --- /dev/null +++ b/solver-rs/aux/boards/normal/14.json @@ -0,0 +1 @@ +{"field": [[{"Number": {"value": 1, "suit": "Black"}}, {"Number": {"value": 5, "suit": "Red"}}, {"Number": {"value": 2, "suit": "Red"}}, {"Number": {"value": 2, "suit": "Green"}}, {"Number": {"value": 6, "suit": "Green"}}], ["Hua", {"Special": "Zhong"}, {"Special": "Fa"}, {"Number": {"value": 8, "suit": "Red"}}, {"Number": {"value": 3, "suit": "Red"}}], [{"Special": "Bai"}, {"Special": "Fa"}, {"Special": "Bai"}, {"Number": {"value": 7, "suit": "Green"}}, {"Number": {"value": 3, "suit": "Green"}}], [{"Number": {"value": 9, "suit": "Black"}}, {"Number": {"value": 4, "suit": "Green"}}, {"Number": {"value": 1, "suit": "Red"}}, {"Special": "Fa"}, {"Number": {"value": 9, "suit": "Green"}}], [{"Special": "Zhong"}, {"Number": {"value": 6, "suit": "Red"}}, {"Number": {"value": 5, "suit": "Green"}}, {"Number": {"value": 7, "suit": "Black"}}, {"Number": {"value": 2, "suit": "Black"}}], [{"Number": {"value": 9, "suit": "Red"}}, {"Special": "Zhong"}, {"Number": {"value": 6, "suit": "Black"}}, {"Number": {"value": 5, "suit": "Black"}}, {"Number": {"value": 8, "suit": "Green"}}], [{"Special": "Bai"}, {"Number": {"value": 1, "suit": "Green"}}, {"Special": "Bai"}, {"Special": "Fa"}, {"Number": {"value": 7, "suit": "Red"}}], [{"Number": {"value": 8, "suit": "Black"}}, {"Number": {"value": 4, "suit": "Black"}}, {"Number": {"value": 3, "suit": "Black"}}, {"Number": {"value": 4, "suit": "Red"}}, {"Special": "Zhong"}]], "hua_set": false, "bunker": ["Empty", "Empty", "Empty"], "goal": [null, null, null]} diff --git a/solver-rs/aux/boards/normal/15.json b/solver-rs/aux/boards/normal/15.json new file mode 100644 index 0000000..0349a7d --- /dev/null +++ b/solver-rs/aux/boards/normal/15.json @@ -0,0 +1 @@ +{"field": [[{"Special": "Zhong"}, {"Number": {"value": 7, "suit": "Red"}}, {"Special": "Bai"}, {"Number": {"value": 3, "suit": "Black"}}], ["Hua", {"Number": {"value": 9, "suit": "Red"}}, {"Number": {"value": 9, "suit": "Black"}}], [{"Number": {"value": 7, "suit": "Green"}}, {"Special": "Fa"}, {"Number": {"value": 2, "suit": "Red"}}, {"Special": "Fa"}, {"Number": {"value": 3, "suit": "Green"}}], [{"Special": "Zhong"}, {"Number": {"value": 5, "suit": "Red"}}, {"Special": "Bai"}, {"Number": {"value": 3, "suit": "Red"}}, {"Special": "Bai"}], [{"Number": {"value": 6, "suit": "Red"}}, {"Special": "Fa"}, {"Number": {"value": 6, "suit": "Green"}}, {"Number": {"value": 5, "suit": "Black"}}, {"Special": "Fa"}], [{"Number": {"value": 8, "suit": "Red"}}, {"Number": {"value": 1, "suit": "Green"}}, {"Number": {"value": 7, "suit": "Black"}}, {"Number": {"value": 4, "suit": "Black"}}, {"Special": "Zhong"}], [{"Number": {"value": 9, "suit": "Green"}}, {"Number": {"value": 2, "suit": "Green"}}, {"Number": {"value": 8, "suit": "Green"}}, {"Special": "Zhong"}, {"Number": {"value": 8, "suit": "Black"}}], [{"Number": {"value": 4, "suit": "Red"}}, {"Number": {"value": 6, "suit": "Black"}}, {"Number": {"value": 5, "suit": "Green"}}, {"Number": {"value": 4, "suit": "Green"}}, {"Special": "Bai"}]], "hua_set": false, "bunker": ["Empty", "Empty", "Empty"], "goal": [{"value": 1, "suit": "Red"}, {"value": 2, "suit": "Black"}, null]} diff --git a/solver-rs/aux/boards/normal/16.json b/solver-rs/aux/boards/normal/16.json new file mode 100644 index 0000000..269ee39 --- /dev/null +++ b/solver-rs/aux/boards/normal/16.json @@ -0,0 +1 @@ +{"field": [[{"Number": {"value": 6, "suit": "Green"}}, {"Number": {"value": 5, "suit": "Green"}}, {"Number": {"value": 4, "suit": "Red"}}, {"Number": {"value": 4, "suit": "Green"}}, {"Special": "Fa"}], [{"Number": {"value": 8, "suit": "Black"}}, {"Number": {"value": 6, "suit": "Black"}}, {"Special": "Zhong"}, {"Number": {"value": 9, "suit": "Black"}}, {"Number": {"value": 7, "suit": "Green"}}], [{"Special": "Zhong"}, {"Number": {"value": 4, "suit": "Black"}}, {"Number": {"value": 2, "suit": "Green"}}, {"Special": "Bai"}, {"Special": "Zhong"}], [{"Number": {"value": 1, "suit": "Green"}}, {"Number": {"value": 3, "suit": "Green"}}, {"Number": {"value": 5, "suit": "Black"}}, {"Special": "Fa"}, {"Special": "Fa"}], [{"Number": {"value": 8, "suit": "Red"}}, {"Special": "Zhong"}, {"Number": {"value": 7, "suit": "Red"}}], [{"Special": "Fa"}, {"Special": "Bai"}, {"Number": {"value": 2, "suit": "Red"}}, "Hua", {"Special": "Bai"}], [{"Number": {"value": 2, "suit": "Black"}}, {"Number": {"value": 8, "suit": "Green"}}, {"Number": {"value": 7, "suit": "Black"}}, {"Special": "Bai"}, {"Number": {"value": 9, "suit": "Red"}}], [{"Number": {"value": 3, "suit": "Red"}}, {"Number": {"value": 3, "suit": "Black"}}, {"Number": {"value": 9, "suit": "Green"}}, {"Number": {"value": 5, "suit": "Red"}}, {"Number": {"value": 6, "suit": "Red"}}]], "hua_set": false, "bunker": ["Empty", "Empty", "Empty"], "goal": [{"value": 1, "suit": "Red"}, {"value": 1, "suit": "Black"}, null]} diff --git a/solver-rs/aux/boards/normal/17.json b/solver-rs/aux/boards/normal/17.json new file mode 100644 index 0000000..43ec0ca --- /dev/null +++ b/solver-rs/aux/boards/normal/17.json @@ -0,0 +1 @@ +{"field": [[{"Number": {"value": 5, "suit": "Black"}}, {"Number": {"value": 2, "suit": "Red"}}, {"Special": "Zhong"}, {"Number": {"value": 3, "suit": "Black"}}, {"Number": {"value": 9, "suit": "Green"}}], ["Hua", {"Number": {"value": 2, "suit": "Green"}}, {"Number": {"value": 9, "suit": "Red"}}, {"Number": {"value": 3, "suit": "Green"}}, {"Number": {"value": 7, "suit": "Green"}}], [{"Number": {"value": 2, "suit": "Black"}}, {"Number": {"value": 1, "suit": "Green"}}, {"Number": {"value": 6, "suit": "Black"}}, {"Number": {"value": 4, "suit": "Green"}}, {"Special": "Zhong"}], [{"Number": {"value": 3, "suit": "Red"}}, {"Number": {"value": 6, "suit": "Red"}}, {"Special": "Bai"}, {"Number": {"value": 4, "suit": "Red"}}, {"Special": "Fa"}], [{"Special": "Bai"}, {"Number": {"value": 7, "suit": "Black"}}, {"Special": "Fa"}, {"Special": "Bai"}, {"Number": {"value": 6, "suit": "Green"}}], [{"Number": {"value": 9, "suit": "Black"}}, {"Special": "Zhong"}, {"Number": {"value": 5, "suit": "Green"}}, {"Special": "Bai"}, {"Special": "Zhong"}], [{"Number": {"value": 8, "suit": "Green"}}, {"Number": {"value": 4, "suit": "Black"}}, {"Number": {"value": 8, "suit": "Red"}}, {"Number": {"value": 1, "suit": "Red"}}, {"Number": {"value": 7, "suit": "Red"}}], [{"Number": {"value": 1, "suit": "Black"}}, {"Special": "Fa"}, {"Special": "Fa"}, {"Number": {"value": 5, "suit": "Red"}}, {"Number": {"value": 8, "suit": "Black"}}]], "hua_set": false, "bunker": ["Empty", "Empty", "Empty"], "goal": [null, null, null]} diff --git a/solver-rs/aux/boards/normal/18.json b/solver-rs/aux/boards/normal/18.json new file mode 100644 index 0000000..80e543b --- /dev/null +++ b/solver-rs/aux/boards/normal/18.json @@ -0,0 +1 @@ +{"field": [[{"Number": {"value": 5, "suit": "Black"}}, {"Number": {"value": 7, "suit": "Green"}}, {"Special": "Fa"}, {"Number": {"value": 4, "suit": "Red"}}, {"Special": "Zhong"}], [{"Special": "Zhong"}, {"Number": {"value": 3, "suit": "Red"}}, {"Special": "Fa"}, {"Number": {"value": 9, "suit": "Black"}}, {"Number": {"value": 9, "suit": "Green"}}], [{"Number": {"value": 1, "suit": "Red"}}, {"Special": "Bai"}, {"Number": {"value": 2, "suit": "Red"}}, {"Special": "Zhong"}, {"Number": {"value": 3, "suit": "Black"}}], [{"Special": "Bai"}, {"Number": {"value": 7, "suit": "Black"}}, {"Number": {"value": 2, "suit": "Black"}}, {"Special": "Bai"}, {"Number": {"value": 4, "suit": "Green"}}], [{"Number": {"value": 3, "suit": "Green"}}, {"Number": {"value": 6, "suit": "Green"}}, {"Special": "Zhong"}, {"Number": {"value": 8, "suit": "Black"}}, {"Number": {"value": 6, "suit": "Black"}}], [{"Number": {"value": 2, "suit": "Green"}}, {"Number": {"value": 4, "suit": "Black"}}, "Hua", {"Number": {"value": 7, "suit": "Red"}}, {"Special": "Bai"}], [{"Number": {"value": 1, "suit": "Green"}}, {"Number": {"value": 5, "suit": "Green"}}, {"Number": {"value": 5, "suit": "Red"}}, {"Special": "Fa"}, {"Number": {"value": 6, "suit": "Red"}}], [{"Number": {"value": 8, "suit": "Green"}}, {"Number": {"value": 1, "suit": "Black"}}, {"Special": "Fa"}, {"Number": {"value": 8, "suit": "Red"}}, {"Number": {"value": 9, "suit": "Red"}}]], "hua_set": false, "bunker": ["Empty", "Empty", "Empty"], "goal": [null, null, null]} diff --git a/solver-rs/aux/boards/specific/dragonkill.json b/solver-rs/aux/boards/specific/dragonkill.json new file mode 100644 index 0000000..4ff0ce8 --- /dev/null +++ b/solver-rs/aux/boards/specific/dragonkill.json @@ -0,0 +1,19 @@ +{ + "field": [ + [], + [], + ["Hua", { "Number": { "value": 9, "suit": "Black" } }], + [{ "Special": "Zhong" }], + [{ "Special": "Zhong" }], + [{ "Special": "Zhong" }], + [{ "Special": "Zhong" }], + [] + ], + "goal": [ + { "value": 8, "suit": "Black" }, + { "value": 9, "suit": "Green" }, + { "value": 9, "suit": "Red" } + ], + "hua_set": false, + "bunker": [{ "Blocked": null }, { "Blocked": null }, "Empty"] +} diff --git a/solver-rs/aux/boards/specific/scarce.json b/solver-rs/aux/boards/specific/scarce.json new file mode 100644 index 0000000..5f1033f --- /dev/null +++ b/solver-rs/aux/boards/specific/scarce.json @@ -0,0 +1,19 @@ +{ + "field": [ + [], + [], + ["Hua", { "Number": { "value": 9, "suit": "Black" } }], + [], + [], + [], + [], + [] + ], + "goal": [ + { "value": 8, "suit": "Black" }, + { "value": 9, "suit": "Green" }, + { "value": 9, "suit": "Red" } + ], + "hua_set": false, + "bunker": [{ "Blocked": null }, { "Blocked": null }, { "Blocked": null }] +} diff --git a/solver-rs/aux/boards/specific/solved.json b/solver-rs/aux/boards/specific/solved.json new file mode 100644 index 0000000..94bdc41 --- /dev/null +++ b/solver-rs/aux/boards/specific/solved.json @@ -0,0 +1,10 @@ +{ + "field": [[], [], [], [], [], [], [], []], + "goal": [ + { "value": 9, "suit": "Black" }, + { "value": 9, "suit": "Green" }, + { "value": 9, "suit": "Red" } + ], + "hua_set": true, + "bunker": [{ "Blocked": null }, { "Blocked": null }, { "Blocked": null }] +} diff --git a/solver-rs/clippy.cfg b/solver-rs/clippy.cfg new file mode 100644 index 0000000..d4b91a7 --- /dev/null +++ b/solver-rs/clippy.cfg @@ -0,0 +1,37 @@ +#![warn( + clippy::all, + clippy::restriction, + clippy::pedantic, + clippy::nursery, + clippy::cargo +)] +#![allow(clippy::cargo)] +// Style choices +#![allow( + clippy::missing_docs_in_private_items, + clippy::needless_return, + clippy::get_unwrap, + clippy::indexing_slicing, + clippy::explicit_iter_loop +)] +// Way too pedantic +#![allow(clippy::integer_arithmetic)] +// Useless +#![allow(clippy::missing_inline_in_public_items, clippy::missing_const_for_fn)] +// Useful for production +#![allow( + clippy::use_debug, + clippy::print_stdout, + clippy::dbg_macro, + clippy::panic +)] +// Useful for improving code robustness +#![allow( + clippy::cast_possible_truncation, + clippy::cast_possible_wrap, + clippy::option_unwrap_used, + // clippy::result_unwrap_used, + // clippy::wildcard_enum_match_arm +)] +#![allow(clippy::trivially_copy_pass_by_ref)] +#![allow(dead_code)] \ No newline at end of file diff --git a/solver-rs/lib/action_optimization/Cargo.toml b/solver-rs/lib/action_optimization/Cargo.toml new file mode 100644 index 0000000..b257e72 --- /dev/null +++ b/solver-rs/lib/action_optimization/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "action_optimization" +version = "0.1.0" +authors = ["Lukas Wölfer "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +serde = {version="1.0.105",features=["derive"]} +serde_json = "1.0" +petgraph = "0.5.1" + +board = {path = "../board"} +actions = {path = "../actions"} \ No newline at end of file diff --git a/solver-rs/lib/action_optimization/src/drawing.rs b/solver-rs/lib/action_optimization/src/drawing.rs new file mode 100644 index 0000000..cc04bb6 --- /dev/null +++ b/solver-rs/lib/action_optimization/src/drawing.rs @@ -0,0 +1,98 @@ +use super::graph_entity::{to_graph, ActionGraph, RelationType}; +use std::{ + path::Path, + process::{Command, Stdio}, +}; + +#[must_use] +pub fn dot_actions(actions: &[actions::All]) -> String { + return dot_actiongraph(&to_graph(actions)); +} + +#[must_use] +fn dot_actiongraph(graph: &ActionGraph) -> String { + let edge_attr = |relation_type: &RelationType| { + let edge_style = match relation_type { + RelationType::Move => "bold", + RelationType::Unblock + | RelationType::Clear + | RelationType::Socket + | RelationType::Goal => "solid", + }; + let edge_color = match relation_type { + RelationType::Move => "black", + RelationType::Unblock => "green", + RelationType::Clear => "grey", + RelationType::Socket => "red", + RelationType::Goal => "blue", + }; + return format!("style=\"{}\" color=\"{}\"", edge_style, edge_color); + }; + let node_attr = |action: &actions::All| { + let node_color = match action { + actions::All::Bunkerize(_) | actions::All::Move(_) => "white", + actions::All::DragonKill(_) => "silver", + actions::All::Goal(_) => "blue", + actions::All::HuaKill(_) => "gold", + }; + return format!( + r#"style="filled" fillcolor="{}" label="{}" shape="rect""#, + node_color, + action.to_string().replace(r#"""#, r#"\""#) + ); + }; + let dot_rep = petgraph::dot::Dot::with_attr_getters( + &graph, + &[ + petgraph::dot::Config::EdgeNoLabel, + petgraph::dot::Config::NodeNoLabel, + ], + &|_mygraph, myedge| return edge_attr(myedge.weight()), + &|_mygraph, (_index, action)| { + return node_attr(action); + }, + ) + .to_string(); + return dot_rep; +} + +pub fn draw_graph(graph: &ActionGraph, path: &Path) -> Result<(), Box> { + //! # Errors + //! File write error + let input = dot_actiongraph(graph); + let mut child = Command::new("dot") + .args(&["-Tsvg", "-o", path.to_string_lossy().as_ref()]) + .stdin(Stdio::piped()) + .stderr(Stdio::piped()) + .stdout(Stdio::piped()) + .spawn()?; + + std::io::Write::write_all( + child + .stdin + .as_mut() + .ok_or("Child process stdin has not been captured!")?, + input.as_bytes(), + )?; + + let output = child.wait_with_output()?; + if !output.status.success() { + println!( + "Dot failed\n{}\n{}", + std::str::from_utf8(&output.stdout).unwrap(), + std::str::from_utf8(&output.stderr).unwrap() + ); + // No idea how to return a custom error here + } + return Result::Ok(()); +} + +pub fn draw_actions( + actions: &[actions::All], + path: &Path, +) -> Result<(), Box> { + //! # Errors + //! File write error + let graph = to_graph(actions); + return draw_graph(&graph, path); +} diff --git a/solver-rs/lib/action_optimization/src/graph_entity.rs b/solver-rs/lib/action_optimization/src/graph_entity.rs new file mode 100644 index 0000000..e3ea368 --- /dev/null +++ b/solver-rs/lib/action_optimization/src/graph_entity.rs @@ -0,0 +1,87 @@ +use super::relation::{ + get_clear_parents, get_destination_parent, get_goal_parent, get_move_parents, +}; + +#[derive(Debug, Copy, Clone, PartialEq)] +pub enum RelationType { + Move, + Unblock, + Clear, + Socket, + Goal, +} + +impl std::fmt::Display for RelationType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let stringed = match self { + Self::Move => "Move", + Self::Unblock => "Unblock", + Self::Clear => "Clear", + Self::Socket => "Socket", + Self::Goal => "Goal", + }; + return write!(f, "{}", stringed); + } +} +pub type ActionGraph = petgraph::stable_graph::StableDiGraph; + +pub fn to_graph(actions: &[actions::All]) -> ActionGraph { + let mut x = ActionGraph::new(); + + macro_rules! relations { + ($actions:expr, $index: expr, $( $x:expr, $y: expr ),*) => {{ + [ + $( + ($x)($actions, $index).into_iter().map(|b| return (b, $y)).collect::>(), + )* + ] + }}; + } + // can you ActionGraph::from_elements here + for (index, action) in actions.iter().enumerate() { + let current_node = x.add_node(action.clone()); + + let relations = relations!( + actions, + index, + get_move_parents, + RelationType::Move, + get_clear_parents, + RelationType::Clear, + get_goal_parent, + RelationType::Goal + ); + for (parent, relation) in relations.iter().flatten() { + x.add_edge( + petgraph::stable_graph::NodeIndex::new(*parent), + current_node, + *relation, + ); + } + if let Option::Some((parent, relation)) = get_destination_parent(actions, index) { + x.add_edge( + petgraph::stable_graph::NodeIndex::new(parent), + current_node, + relation, + ); + } + } + return x; +} + +pub fn from_graph(graph: &ActionGraph) -> Vec { + match petgraph::algo::toposort(graph, Option::None) { + Ok(topo_actions) => { + let topo_actions = topo_actions + .into_iter() + .map(|index| return graph.node_weight(index).unwrap().clone()) + .collect::>(); + return topo_actions; + } + Err(c) => panic!( + "Could not toposort the graph, {:#?}, Graph: {:?}", + c, + super::draw_graph(graph, std::path::Path::new("cycle_graph.svg")) + ), + } +} diff --git a/solver-rs/lib/action_optimization/src/lib.rs b/solver-rs/lib/action_optimization/src/lib.rs new file mode 100644 index 0000000..9855fe8 --- /dev/null +++ b/solver-rs/lib/action_optimization/src/lib.rs @@ -0,0 +1,52 @@ +#![warn( + clippy::all, + clippy::restriction, + clippy::pedantic, + clippy::nursery, + clippy::cargo +)] +#![allow(clippy::cargo)] +// Style choices +#![allow( + clippy::missing_docs_in_private_items, + clippy::needless_return, + clippy::get_unwrap, + clippy::indexing_slicing, + clippy::explicit_iter_loop +)] +// Way too pedantic +#![allow(clippy::integer_arithmetic)] +// Useless +#![allow(clippy::missing_inline_in_public_items, clippy::missing_const_for_fn)] +// Useful for production +#![allow( + clippy::use_debug, + clippy::print_stdout, + clippy::dbg_macro, + clippy::panic +)] +// Useful for improving code robustness +#![allow( + clippy::cast_possible_truncation, + clippy::cast_possible_wrap, + clippy::option_unwrap_used, + clippy::option_expect_used, + clippy::as_conversions, + clippy::result_unwrap_used, + // clippy::wildcard_enum_match_arm +)] +#![allow(clippy::trivially_copy_pass_by_ref)] +#![allow(dead_code)] +mod drawing; +mod graph_entity; +mod optimize; +pub use optimize::optimize; +mod relation; +mod util; +// mod graph_check; +pub use drawing::*; +pub mod test_actions; + + +#[cfg(test)] +mod tests; diff --git a/solver-rs/lib/action_optimization/src/optimize.rs b/solver-rs/lib/action_optimization/src/optimize.rs new file mode 100644 index 0000000..162ece3 --- /dev/null +++ b/solver-rs/lib/action_optimization/src/optimize.rs @@ -0,0 +1,526 @@ +use super::{ + graph_entity::{from_graph, to_graph, ActionGraph, RelationType}, + util::{get_all_cards, get_all_sources}, +}; + +use actions::{Bunkerize, DragonKill, Goal, Move}; +use board::PositionNoGoal; +use std::collections::HashSet; + +use petgraph::visit::{EdgeRef, IntoNodeReferences}; + +pub fn merge_actions( + descendant_action: &actions::All, + parent_action: &actions::All, +) -> Result { + debug_assert_eq!( + get_all_cards(descendant_action), + get_all_cards(parent_action) + ); + match descendant_action { + actions::All::Bunkerize(action) => { + let parent_source = get_all_sources(parent_action.clone()); + if parent_source.len() != 1 { + return Result::Err("Only operates on parents with one source".to_string()); + } + let parent_source = &parent_source[0]; + if action.to_bunker { + match parent_source { + PositionNoGoal::Field(parent_field) => { + return Result::Ok(actions::All::Bunkerize(Bunkerize { + field_position: *parent_field, + ..action.clone() + })); + } + PositionNoGoal::Bunker { .. } => { + return Result::Err("Cannot merge non field move to bunkerize".to_string()); + } + } + } else { + match parent_source { + PositionNoGoal::Field(parent_field) => { + return Result::Ok(actions::All::Move(Move::new( + *parent_field, + action.field_position, + &[action.card.add_hua()], + ))); + } + PositionNoGoal::Bunker { .. } => panic!( + "How can you have two debunkerize actions after following each other?" + ), + } + } + } + actions::All::DragonKill(_) => return Result::Err("Not implemented".to_string()), + actions::All::Goal(action) => { + let parent_source = get_all_sources(parent_action.clone()); + if parent_source.len() != 1 { + return Result::Err("Only operates on parents with one source".to_string()); + } + let parent_source = parent_source.into_iter().next().unwrap(); + return Result::Ok(actions::All::Goal(Goal { + source: parent_source, + ..action.clone() + })); + } + actions::All::HuaKill(_) => { + panic!("How do you have a move parent for a hua kill?"); + } + actions::All::Move(action) => { + let parent_source = get_all_sources(parent_action.clone()); + if parent_source.len() != 1 { + return Result::Err("Only operates on parents with one source".to_string()); + } + let parent_source = parent_source.into_iter().next().unwrap(); + match parent_source { + PositionNoGoal::Field(parent_field) => { + let mut result_action = action.clone(); + result_action.source = parent_field; + return Result::Ok(actions::All::Move(result_action)); + } + PositionNoGoal::Bunker { slot_index } => { + assert!(action.stack_len() == 1); + return Result::Ok(actions::All::Bunkerize(Bunkerize { + bunker_slot_index: slot_index, + card: action.cards()[0].remove_hua(), + field_position: action.destination, + to_bunker: false, + })); + } + } + } + } +} + +fn get_parents( + graph: &ActionGraph, + index: petgraph::stable_graph::NodeIndex, +) -> Vec { + let parent = graph + .edges_directed(index, petgraph::Direction::Incoming) + .filter_map(|x| { + if x.weight() == &RelationType::Move { + return Option::Some(x.source()); + } else { + return Option::None; + } + }); + return parent.collect(); +} + +fn socket_for( + graph: &ActionGraph, + index: petgraph::stable_graph::NodeIndex, +) -> Vec { + return graph + .edges_directed(index, petgraph::Direction::Outgoing) + .filter_map(|x| { + if x.weight() == &RelationType::Socket { + return Option::Some(x.target()); + } else { + return Option::None; + } + }) + .collect(); +} + +/// # Relations when merging nodes +/// - To parent: +/// - Clearing -> To merged node, needs to be cleared no matter destination +/// - Unblocking -> remove +/// - Socketing -> remove +/// - From parent: +/// - Clearing -> From merged node, clears no matter of destination +/// - Unblocking -> From merged node, when to child both nodes can be removed +/// - Socketing -> Abort merging, probably needs to be still there +/// - To child: +/// - Clearing -> Shouldn't happen when there is no traffic between parent +/// - Unblocking -> Still required, keep +/// - Socketing -> Still required, keep +/// - From child: +/// - Clearing -> Should cancel the socket to parent, remove +/// - Unblocking -> Join with incoming unblocking of parent, otherwise cell was always empty +/// - Socketing -> keep, destination stays the same, as such still sockets the target of the relation +fn merge_edges( + graph: &mut ActionGraph, + parent: petgraph::stable_graph::NodeIndex, + child: petgraph::stable_graph::NodeIndex, +) { + let mut addable_edges = Vec::new(); + let mut removable_edges = Vec::new(); + let mut unblock_parent = Option::None; + let mut socket_parent = Option::None; + for parent_dependent in graph.edges_directed(parent, petgraph::Direction::Incoming) { + match parent_dependent.weight() { + RelationType::Socket => socket_parent = Option::Some(parent_dependent.source()), + RelationType::Unblock => unblock_parent = Option::Some(parent_dependent.source()), + RelationType::Move | RelationType::Clear => { + addable_edges.push((parent_dependent.source(), child, *parent_dependent.weight())); + } + RelationType::Goal => panic!("Merging actions does not work on goal actions"), + } + } + for parent_dependent in graph.edges_directed(parent, petgraph::Direction::Outgoing) { + match parent_dependent.weight() { + RelationType::Move => { + debug_assert_eq!(parent_dependent.target(), child); + } + RelationType::Unblock | RelationType::Clear => { + if parent_dependent.target() != child { + addable_edges.push(( + child, + parent_dependent.target(), + *parent_dependent.weight(), + )); + } + } + RelationType::Socket => { + panic!("Cannot merge a parent which provides a socket for an action") + } + RelationType::Goal => panic!("Merging actions does not work on goal actions"), + } + } + for child_dependent in graph.edges_directed(child, petgraph::Direction::Incoming) { + match child_dependent.weight() { + RelationType::Move => { + if get_all_cards(&graph[child]).len() == 1 { + debug_assert_eq!(child_dependent.source(), parent); + } + } + RelationType::Clear => { + if get_all_cards(&graph[child]).len() == 1 { + panic!("What is being cleared between the parent and the child when no other interaction happened in between?\n{:?} {}\n{:?} {}", + parent, graph.node_weight(parent).unwrap(), child, graph.node_weight(child).unwrap()); + } + } + RelationType::Unblock | RelationType::Socket | RelationType::Goal => {} + } + } + for child_dependent in graph.edges_directed(child, petgraph::Direction::Outgoing) { + match child_dependent.weight() { + RelationType::Goal | RelationType::Move | RelationType::Socket => {} + RelationType::Clear => removable_edges.push(child_dependent.id()), + RelationType::Unblock => { + debug_assert!( + !(unblock_parent.is_some() && socket_parent.is_some()), + "Both unblock {:?} and socket {:?} parent for {:?}", + unblock_parent.unwrap(), + socket_parent.unwrap(), + child + ); + if let Option::Some(parent_unblocker) = unblock_parent { + addable_edges.push(( + parent_unblocker, + child_dependent.target(), + *child_dependent.weight(), + )); + removable_edges.push(child_dependent.id()); + } + if let Option::Some(parent_socket) = socket_parent { + addable_edges.push(( + parent_socket, + child_dependent.target(), + RelationType::Socket, + )); + removable_edges.push(child_dependent.id()); + } + } + } + } + for (source, target, weight) in addable_edges { + graph.add_edge(source, target, weight); + } + for edge in removable_edges { + graph.remove_edge(edge); + } + graph.remove_node(parent); +} + +pub fn try_merge( + graph: &mut ActionGraph, + parent: petgraph::stable_graph::NodeIndex, + child: petgraph::stable_graph::NodeIndex, +) -> bool { + if let Result::Ok(new_action) = merge_actions( + graph.node_weight(child).unwrap(), + graph.node_weight(parent).unwrap(), + ) { + *graph.node_weight_mut(child).unwrap() = new_action; + } else { + return false; + } + merge_edges(graph, parent, child); + return true; +} + +/// Remove an action from the graph which has no impact on the board +pub fn delete_null_node(graph: &mut ActionGraph, null_node: petgraph::stable_graph::NodeIndex) { + let join_edge = |graph: &mut ActionGraph, reltype: RelationType| { + let incoming_edge = graph + .edges_directed(null_node, petgraph::Direction::Incoming) + .find_map(|x| { + if x.weight() == &reltype { + return Option::Some(x.source()); + } else { + return Option::None; + } + }); + let outgoing_edge = graph + .edges_directed(null_node, petgraph::Direction::Outgoing) + .find_map(|x| { + if x.weight() == &reltype { + return Option::Some(x.target()); + } else { + return Option::None; + } + }); + if let Option::Some(incoming_edge) = incoming_edge { + if let Option::Some(outgoing_edge) = outgoing_edge { + graph.add_edge(incoming_edge, outgoing_edge, reltype); + } + } + }; + join_edge(graph, RelationType::Move); + join_edge(graph, RelationType::Unblock); + for weird_edge in graph + .edges_directed(null_node, petgraph::Direction::Incoming) + .chain(graph.edges_directed(null_node, petgraph::Direction::Outgoing)) + .filter(|x| { + return x.weight() != &RelationType::Move && x.weight() != &RelationType::Unblock; + }) + { + eprintln!( + "Weird edge while deleting null node\n{}\n{:?} {}\n{:?} {}\n{:?} {}", + weird_edge.weight(), + null_node, + graph.node_weight(null_node).unwrap(), + weird_edge.source(), + graph.node_weight(weird_edge.source()).unwrap(), + weird_edge.target(), + graph.node_weight(weird_edge.target()).unwrap(), + ) + } + graph.remove_node(null_node); +} + +fn try_replace_bunker_slot( + graph: &mut ActionGraph, + index: petgraph::stable_graph::NodeIndex, + parent_slot: u8, + child_slot: u8, +) { + let swap_slot = |slot| { + if slot == child_slot { + return parent_slot; + } else if slot == parent_slot { + return child_slot; + } else { + return slot; + } + }; + match graph.node_weight_mut(index).unwrap() { + actions::All::Bunkerize(Bunkerize { + bunker_slot_index, .. + }) => { + *bunker_slot_index = swap_slot(*bunker_slot_index); + } + actions::All::DragonKill(DragonKill { + source, + destination_slot_index, + .. + }) => { + let slot_index = source.iter_mut().filter_map(|x| { + if let board::PositionNoGoal::Bunker { slot_index } = x { + return Option::Some(slot_index); + } else { + return Option::None; + } + }); + for current_slot in slot_index { + *current_slot = swap_slot(*current_slot); + } + *destination_slot_index = swap_slot(*destination_slot_index); + } + actions::All::Goal(Goal { source, .. }) => { + if let PositionNoGoal::Bunker { slot_index } = source { + *slot_index = swap_slot(*slot_index); + } + } + actions::All::HuaKill(_) | actions::All::Move(_) => { + return; + } + } +} + +fn flip_bunker_slots( + graph: &mut ActionGraph, + index: petgraph::stable_graph::NodeIndex, + parent_slot: u8, + child_slot: u8, +) { + let unblock_move_graph = petgraph::visit::EdgeFiltered::from_fn( + &*graph, + &|x: petgraph::stable_graph::EdgeReference| match x.weight() { + RelationType::Move | RelationType::Unblock => return true, + RelationType::Clear | RelationType::Socket | RelationType::Goal => return false, + }, + ); + let mut visitor = petgraph::visit::Dfs::new(&unblock_move_graph, index); + + while let Option::Some(index) = visitor.next(&*graph) { + try_replace_bunker_slot(graph, index, parent_slot, child_slot); + } +} + +fn is_bunker_loop( + graph: &ActionGraph, + parent: petgraph::stable_graph::NodeIndex, + child: petgraph::stable_graph::NodeIndex, +) -> bool { + if let actions::All::Bunkerize(Bunkerize { + to_bunker: parent_to_bunker, + .. + }) = graph.node_weight(parent).unwrap() + { + if let actions::All::Bunkerize(Bunkerize { to_bunker, .. }) = + graph.node_weight(child).unwrap() + { + if !parent_to_bunker && *to_bunker { + // if *parent_slot == *bunker_slot_index { + // return Option::Some((*parent_slot, *bunker_slot_index)); + // } + return true; + } + } + } + return false; +} + +fn is_field_loop( + graph: &ActionGraph, + parent: petgraph::stable_graph::NodeIndex, + child: petgraph::stable_graph::NodeIndex, +) -> bool { + if let actions::All::Move(move_action) = graph.node_weight(parent).unwrap() { + if let actions::All::Move(child_move_action) = graph.node_weight(child).unwrap() { + debug_assert_eq!(move_action.cards(), child_move_action.cards()); + debug_assert_eq!(move_action.destination, child_move_action.source); + debug_assert_eq!(move_action.stack_len(), 1); + return move_action.source == child_move_action.destination; + } + } + return false; +} + +pub fn merge_step(mut graph: ActionGraph) -> ActionGraph { + let mut used_nodes = HashSet::new(); + let mut mergeable = Vec::new(); + let mut loop_deletion = Vec::new(); + let mut bunker_loop_deletion = Vec::new(); + for (index, _action) in graph.node_references() { + if used_nodes.contains(&index) { + continue; + } + let parents = get_parents(&graph, index); + if parents.len() != 1 { + continue; + } + let parent = parents.into_iter().next().unwrap(); + if used_nodes.contains(&parent) { + continue; + } + + if get_all_cards(graph.node_weight(parent).unwrap()).len() > 1 { + continue; + } + if get_all_cards(graph.node_weight(index).unwrap()).len() > 1 { + continue; + } + if socket_for(&graph, parent) + .into_iter() + .any(|x| return x != index) + { + continue; + } + let filtered_graph = petgraph::visit::EdgeFiltered::from_fn(&graph, |x| { + return !(x.source() == parent && x.target() == index); + }); + if petgraph::algo::has_path_connecting(&filtered_graph, parent, index, Option::None) { + continue; + } + if is_bunker_loop(&graph, parent, index) { + bunker_loop_deletion.push((parent, index)); + } else if is_field_loop(&graph, parent, index) { + loop_deletion.push((parent, index)); + } else { + mergeable.push((parent, index)); + } + used_nodes.insert(parent); + used_nodes.insert(index); + } + for (parent, child) in mergeable { + try_merge(&mut graph, parent, child); + } + for (parent, child) in loop_deletion { + merge_edges(&mut graph, parent, child); + delete_null_node(&mut graph, child); + } + for (parent, child) in bunker_loop_deletion { + let parent_slot = if let actions::All::Bunkerize(Bunkerize { + bunker_slot_index, + to_bunker, + .. + }) = &graph[parent] + { + assert!(!*to_bunker); + *bunker_slot_index + } else { + panic!("Should be bunkerize action") + }; + let child_slot = if let actions::All::Bunkerize(Bunkerize { + bunker_slot_index, + to_bunker, + .. + }) = &graph[child] + { + assert!(*to_bunker); + *bunker_slot_index + } else { + panic!("Should be bunkerize action") + }; + flip_bunker_slots(&mut graph, parent, parent_slot, child_slot); + merge_edges(&mut graph, parent, child); + delete_null_node(&mut graph, child); + } + + return graph; +} + +fn fix_dragonkill_destination(actions: &[actions::All]) -> Vec { + let graph = to_graph(actions); + let result = graph + .node_indices() + .map(|node| return graph.node_weight(node).unwrap().clone()) + .collect(); + return result; +} + +fn fix_goal_ordering(actions: &[actions::All]) -> Vec { + return actions.to_vec(); +} + +#[must_use] +pub fn optimize(actions: &[actions::All]) -> Vec { + let mut graph = to_graph(actions); + let mut last_length = graph.node_count(); + loop { + graph = merge_step(graph); + if graph.node_count() == last_length { + break; + } + last_length = graph.node_count(); + } + + let optimized_sequence = from_graph(&graph); + return fix_goal_ordering(&fix_dragonkill_destination(&optimized_sequence)); +} diff --git a/solver-rs/lib/action_optimization/src/relation.rs b/solver-rs/lib/action_optimization/src/relation.rs new file mode 100644 index 0000000..4b601bc --- /dev/null +++ b/solver-rs/lib/action_optimization/src/relation.rs @@ -0,0 +1,149 @@ +use super::{ + graph_entity::RelationType, + util::{ + get_all_bottom_sources, get_all_destinations, get_all_sources, get_all_top_sources, + get_destination, get_top_destination, search_parent_tree, top_card, + }, +}; +use actions::{Goal, Move}; +use board::PositionNoGoal; +pub fn get_move_parents(actions: &[actions::All], current_action: usize) -> Vec { + let result = get_all_sources(actions[current_action].clone()) + .into_iter() + .filter_map(|cur_source_pos| { + let is_move_parent = |other_action: &actions::All| { + let destinations = + get_all_destinations(other_action.clone()) + .into_iter() + .any(|cur_dest_pos| { + return cur_dest_pos == cur_source_pos; + }); + return destinations; + }; + + let source_action = search_parent_tree(actions, current_action, is_move_parent); + return source_action.map(|(index, _)| return index); + }) + .collect(); + return result; +} +fn get_unblocking_parent(actions: &[actions::All], current_action: usize) -> Option { + let destination = get_destination(&actions[current_action])?; + let is_unblocking = |other_action: &actions::All| { + return get_all_sources(other_action.clone()) + .into_iter() + .any(|source| return source == destination); + }; + return search_parent_tree(actions, current_action, is_unblocking) + .filter(|&(_, found_action)| { + if let actions::All::Move(Move { ref source, .. }) = found_action { + return board::Position::Field(*source) == destination; + } + return true; + }) + .map(|(index, _)| return index); +} + +fn get_socket_parent(actions: &[actions::All], current_action: usize) -> Option { + let top_action = get_destination(&actions[current_action]); + + if let Option::Some(board::Position::Field(top_action)) = top_action { + let is_socket = |action: &actions::All| { + let socket_destination = get_top_destination(action.clone()); + if let Option::Some(board::Position::Field(destination)) = socket_destination { + return top_card(&destination) == top_action; + } + return false; + }; + let added_socket = + search_parent_tree(actions, current_action, is_socket).map(|(index, _)| { + return index; + }); + let unblocking_parent = get_unblocking_parent(actions, current_action); + if added_socket < unblocking_parent { + return Option::None; + } else { + return added_socket; + } + } + return Option::None; +} + +pub fn get_destination_parent( + actions: &[actions::All], + current_action: usize, +) -> Option<(usize, RelationType)> { + let socket_parent = get_socket_parent(actions, current_action); + let unblock_parent = get_unblocking_parent(actions, current_action); + if socket_parent.is_none() && unblock_parent.is_none() { + return Option::None; + } else if socket_parent > unblock_parent { + return Option::Some((socket_parent.unwrap(), RelationType::Socket)); + } else { + return Option::Some((unblock_parent.unwrap(), RelationType::Unblock)); + } +} + +/// Actions which moved cards on top of other cards away +pub fn get_clear_parents(actions: &[actions::All], current_action: usize) -> Vec { + let filter_fields = |x: PositionNoGoal| { + if let PositionNoGoal::Field(f) = x { + return Some(f); + } else { + return None; + } + }; + let source_positions = get_all_top_sources(&actions[current_action]); + + let parents: Vec = source_positions + .into_iter() + .filter_map(|current_source_pos| { + let current_source_pos = filter_fields(current_source_pos)?; + let latest_moves = get_move_parents(actions, current_action); + let latest_move = if let actions::All::DragonKill(_) = actions[current_action] { + latest_moves + .into_iter() + .find(|index| { + return get_destination(&actions[*index]) + == Option::Some(board::Position::Field(current_source_pos)); + }) + .unwrap_or(0) + } else { + latest_moves.into_iter().max().unwrap_or(0) + }; + let is_clearing = move |other_action: &actions::All| { + let sources = get_all_bottom_sources(other_action); + let clear_parent = sources + .into_iter() + .filter_map(filter_fields) + .any(|cur_dest_pos| return top_card(¤t_source_pos) == cur_dest_pos); + + return clear_parent; + }; + return search_parent_tree(actions, current_action, is_clearing) + .map(|(index, _)| return index) + .filter(|index| return *index >= latest_move); + }) + .collect(); + return parents; +} + +pub fn get_goal_parent(actions: &[actions::All], current_action: usize) -> Option { + if let actions::All::Goal(Goal { card, .. }) = &actions[current_action] { + let is_successive_goal = move |other_action: &actions::All| { + if let actions::All::Goal(Goal { + card: other_card, .. + }) = other_action + { + return other_card.value + 1 == card.value && other_card.suit == card.suit; + } + return false; + }; + if card.value > 1 { + let parent_goal = search_parent_tree(actions, current_action, is_successive_goal) + .map(|(index, _)| return index); + return parent_goal; + } + } + return Option::None; +} diff --git a/solver-rs/lib/action_optimization/src/test_actions.rs b/solver-rs/lib/action_optimization/src/test_actions.rs new file mode 100644 index 0000000..011001f --- /dev/null +++ b/solver-rs/lib/action_optimization/src/test_actions.rs @@ -0,0 +1,20 @@ +// This is incredibly shit, as other crates call this macro with _their_ CARGO_MANIFEST_DIR. Ideally we would move +// the boards into the board crate, and use the path of the board crate. But it seems to be really hard to get this done with +// macros, and const variables can't be used by macros, so we're using this hack for now. +#[macro_export] +macro_rules! TEST_ACTION_ROOT { + () => { + concat!(env!("CARGO_MANIFEST_DIR"), + "/../../aux/actions/") + } +} + +#[macro_export] +macro_rules! load_test_action { + ( $relpath:expr ) => { + { + return serde_json::from_str::>(include_str!(concat!($crate::TEST_ACTION_ROOT!(), + $relpath))); + } + }; +} \ No newline at end of file diff --git a/solver-rs/lib/action_optimization/src/tests.rs b/solver-rs/lib/action_optimization/src/tests.rs new file mode 100644 index 0000000..aa6cbaf --- /dev/null +++ b/solver-rs/lib/action_optimization/src/tests.rs @@ -0,0 +1,66 @@ +use crate::{draw_graph, graph_entity::to_graph}; +use std::str::FromStr; +#[test] +#[ignore] +pub fn optimize_bunker_loop() { + use actions::{All, Bunkerize, Goal}; + use board::FieldPosition; + let numbercard = board::NumberCard { + suit: board::NumberCardColor::Red, + value: 1, + }; + let zhong_card = board::CardType::Number(numbercard.clone()); + let actions = vec![ + All::Bunkerize(Bunkerize { + bunker_slot_index: 0, + card: zhong_card.remove_hua(), + to_bunker: false, + field_position: FieldPosition::new(2, 0), + }), + All::Bunkerize(Bunkerize { + bunker_slot_index: 2, + card: zhong_card.remove_hua(), + to_bunker: true, + field_position: FieldPosition::new(2, 0), + }), + All::Goal(Goal { + card: numbercard, + goal_slot_index: 0, + source: board::PositionNoGoal::Bunker { slot_index: 2 }, + }), + ]; + let graph = to_graph(&actions); + draw_graph(&graph, std::path::Path::new("unopt_bunker.svg")).unwrap(); + let graph = crate::optimize::merge_step(graph); + draw_graph(&graph, std::path::Path::new("opt_bunker.svg")).unwrap(); +} + +#[test] +pub fn all_boards_correct() -> Result<(), Box> { + for i in 1..19 { + let action_string = + std::fs::read_to_string(std::format!("{}/{:02}.json", crate::TEST_ACTION_ROOT!(), i))?; + + let actions: Vec = serde_json::from_str(&action_string)?; + + let board_string = std::fs::read_to_string(std::format!( + "{}/normal/{:02}.json", + board::TEST_BOARD_ROOT!(), + i + ))?; + let src_board = board::Board::from_str(&board_string)?; + let mut board = src_board.clone(); + for action in actions.iter() { + action.apply(&mut board); + } + assert!(board.solved()); + let actions = crate::optimize(&actions); + let mut board = src_board; + for (index, action) in actions.into_iter().enumerate() { + println!("{}", index); + action.apply(&mut board); + } + assert!(board.solved()); + } + return Result::Ok(()); +} diff --git a/solver-rs/lib/action_optimization/src/util.rs b/solver-rs/lib/action_optimization/src/util.rs new file mode 100644 index 0000000..99c2ae6 --- /dev/null +++ b/solver-rs/lib/action_optimization/src/util.rs @@ -0,0 +1,173 @@ +use actions::{Bunkerize, DragonKill, Goal, HuaKill, Move}; +use board::{CardType, FieldPosition}; +use std::convert::TryFrom; + +fn node_name(index: usize) -> String { + return format!("action_{:04}", index); +} + +/// Position on top of this position (increments `position.row_index` by one) +pub fn top_card(position: &FieldPosition) -> FieldPosition { + return FieldPosition::new(position.column(), position.row() + 1); +} + +pub fn column_range(position: &FieldPosition, count: usize) -> Vec { + return (0..count) + .map(|i| { + return FieldPosition::new( + position.column(), + position.row() + u8::try_from(i).unwrap(), + ); + }) + .collect(); +} + +pub fn get_all_sources(action: actions::All) -> Vec { + match action { + actions::All::Bunkerize(Bunkerize { + bunker_slot_index, + to_bunker, + field_position, + .. + }) => { + if to_bunker { + return vec![board::PositionNoGoal::Field(field_position)]; + } else { + return vec![board::PositionNoGoal::Bunker { + slot_index: bunker_slot_index, + }]; + } + } + actions::All::DragonKill(DragonKill { source, .. }) => { + return source.to_vec(); + } + actions::All::Goal(Goal { source, .. }) => { + return vec![source]; + } + actions::All::HuaKill(HuaKill { field_position }) => { + return vec![board::PositionNoGoal::Field(field_position)] + } + actions::All::Move(move_action) => { + return column_range(&move_action.source, usize::from(move_action.stack_len())) + .into_iter() + .map(board::PositionNoGoal::Field) + .collect() + } + } +} + +pub fn get_all_top_sources(action: &actions::All) -> Vec { + if let actions::All::Move(move_action) = &action { + return vec![board::PositionNoGoal::Field(FieldPosition::new( + move_action.source.column(), + move_action.source.row() + move_action.stack_len() - 1, + ))]; + } else { + return get_all_sources(action.clone()); + }; +} + +pub fn get_all_bottom_sources(action: &actions::All) -> Vec { + if let actions::All::Move(Move { source, .. }) = &action { + return vec![board::PositionNoGoal::Field(*source)]; + } else { + return get_all_sources(action.clone()); + }; +} + +pub fn get_all_cards(action: &actions::All) -> Vec { + match action { + actions::All::Bunkerize(Bunkerize { card, .. }) => return vec![card.add_hua()], /* Does this actually work? */ + actions::All::DragonKill(DragonKill { card, .. }) => { + return vec![ + CardType::Special(card.clone()), + CardType::Special(card.clone()), + CardType::Special(card.clone()), + CardType::Special(card.clone()), + ] + } + actions::All::Goal(Goal { card, .. }) => return vec![CardType::Number(card.clone())], + actions::All::HuaKill(_) => return vec![CardType::Hua], + actions::All::Move(move_action) => return move_action.cards(), + } +} + +pub fn get_destination(action: &actions::All) -> Option { + match action { + actions::All::Bunkerize(Bunkerize { + field_position, + to_bunker, + bunker_slot_index, + .. + }) => { + if *to_bunker { + return Option::Some(board::Position::Bunker { + slot_index: *bunker_slot_index, + }); + } else { + return Option::Some(board::Position::Field(*field_position)); + } + } + actions::All::DragonKill(DragonKill { + destination_slot_index, + .. + }) => { + return Option::Some(board::Position::Bunker { + slot_index: *destination_slot_index, + }); + } + actions::All::Goal(Goal { + goal_slot_index, .. + }) => { + return Option::Some(board::Position::Goal { + slot_index: *goal_slot_index, + }); + } + actions::All::HuaKill(_) => return Option::None, + actions::All::Move(Move { destination, .. }) => { + return Option::Some(board::Position::Field(*destination)); + } + } +} + +/// Returns the destination of a move, or the topmost card in its destination when moving multiple cards +pub fn get_top_destination(action: actions::All) -> Option { + if let actions::All::Move(move_action) = action { + return Option::Some(board::Position::Field(FieldPosition::new( + move_action.destination.column(), + move_action.destination.row() + move_action.stack_len() - 1, + ))); + } else { + return get_destination(&action); + }; +} + +pub fn get_all_destinations(action: actions::All) -> Vec { + if let actions::All::Move(move_action) = action { + return column_range( + &move_action.destination, + usize::from(move_action.stack_len()), + ) + .into_iter() + .map(board::Position::Field) + .collect(); + } else { + return get_destination(&action).into_iter().collect(); + }; +} + +pub fn search_parent_tree( + actions: &[actions::All], + current_action: usize, + predicate: F, +) -> Option<(usize, &actions::All)> +where + F: Fn(&actions::All) -> bool, +{ + return actions + .iter() + .enumerate() + .take(current_action) + .rev() + .find(|&(_, action)| return predicate(action)); +} diff --git a/solver-rs/lib/actions/Cargo.toml b/solver-rs/lib/actions/Cargo.toml new file mode 100644 index 0000000..d963305 --- /dev/null +++ b/solver-rs/lib/actions/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "actions" +version = "0.1.0" +authors = ["Lukas Wölfer "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +serde = {version="1.0.105",features=["derive"]} +serde_json = "1.0" +enum-iterator = "0.6.0" + +board = {path = "../board"} \ No newline at end of file diff --git a/solver-rs/lib/actions/src/base.rs b/solver-rs/lib/actions/src/base.rs new file mode 100644 index 0000000..2bd718a --- /dev/null +++ b/solver-rs/lib/actions/src/base.rs @@ -0,0 +1,405 @@ +use board::{ + Board, BunkerSlot, CardType, CardTypeNoHua, FieldPosition, NumberCard, PositionNoGoal, + SpecialCardType, +}; + +use serde::{Deserialize, Serialize}; + +pub(super) trait BoardApplication { + fn apply(&self, solboard: &mut Board); + fn undo(&self, solboard: &mut Board); + fn can_apply(&self, solboard: &Board) -> bool; + fn can_undo(&self, solboard: &Board) -> bool; + fn checked_apply(&self, solboard: &mut Board) -> bool { + if self.can_apply(solboard) { + self.apply(solboard); + return true; + } + return false; + } + fn checked_undo(&self, solboard: &mut Board) -> bool { + if self.can_undo(solboard) { + self.undo(solboard); + return true; + } + return false; + } +} + +fn can_pop_top(solboard: &Board, position: &PositionNoGoal, card: &CardType) -> bool { + match position { + PositionNoGoal::Field(fieldpos) => { + if solboard.field[usize::from(fieldpos.column())] + .last() + .expect("Trying to pop top of empty field stack") + != card + { + return false; + } + } + PositionNoGoal::Bunker { slot_index } => { + if solboard.bunker[usize::from(*slot_index)] != BunkerSlot::Stash(card.remove_hua()) { + return false; + } + } + }; + return true; +} + +fn pop_top(solboard: &mut Board, position: &PositionNoGoal, card: &CardType) { + debug_assert!(can_pop_top(solboard, position, card)); + match position { + PositionNoGoal::Field(fieldpos) => { + solboard + .field + .get_mut(usize::from(fieldpos.column())) + .expect("Column index fucked") + .pop(); + } + PositionNoGoal::Bunker { slot_index } => { + solboard.bunker[usize::from(*slot_index)] = BunkerSlot::Empty; + } + } +} + +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] +pub struct Goal { + pub card: NumberCard, + pub source: PositionNoGoal, + pub goal_slot_index: u8, +} + +impl BoardApplication for Goal { + fn can_apply(&self, solboard: &Board) -> bool { + match &solboard.goal[usize::from(self.goal_slot_index)] { + Option::Some(NumberCard { value, suit }) => { + if self.card.value != *value + 1 { + return false; + } + if self.card.suit != *suit { + return false; + } + } + Option::None => { + if self.card.value != 1 { + return false; + } + } + } + if !can_pop_top(solboard, &self.source, &CardType::Number(self.card.clone())) { + return false; + } + return true; + } + fn can_undo(&self, _solboard: &Board) -> bool { + return true; + } + fn apply(&self, solboard: &mut Board) { + pop_top(solboard, &self.source, &CardType::Number(self.card.clone())); + *solboard + .goal + .get_mut(usize::from(self.goal_slot_index)) + .expect("Slot index fucked") = Option::Some(self.card.clone()); + } + fn undo(&self, solboard: &mut Board) { + match &self.source { + PositionNoGoal::Field(position) => { + solboard + .field + .get_mut(usize::from(position.column())) + .expect("Column index fucked") + .push(CardType::Number(self.card.clone())); + } + PositionNoGoal::Bunker { slot_index } => { + solboard.bunker[usize::from(*slot_index)] = + BunkerSlot::Stash(CardTypeNoHua::Number(self.card.clone())); + } + } + if self.card.value == 1 { + solboard.goal[usize::from(self.goal_slot_index)] = Option::None; + } else { + solboard.goal[usize::from(self.goal_slot_index)] = Option::Some(NumberCard { + suit: self.card.suit.clone(), + value: self.card.value - 1, + }); + } + } +} + +impl std::fmt::Display for Goal { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + return write!( + f, + "Goal {} from {} to slot #{}", + self.card, self.source, self.goal_slot_index + ); + } +} +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] +pub struct DragonKill { + pub card: SpecialCardType, + pub source: [PositionNoGoal; 4], + pub destination_slot_index: u8, +} + +impl BoardApplication for DragonKill { + fn apply(&self, solboard: &mut Board) { + for position in &self.source { + pop_top(solboard, position, &CardType::Special(self.card.clone())); + } + solboard.bunker[usize::from(self.destination_slot_index)] = + BunkerSlot::Blocked(Option::Some(self.card.clone())); + } + fn undo(&self, solboard: &mut Board) { + solboard.bunker[usize::from(self.destination_slot_index)] = BunkerSlot::Empty; + for position in &self.source { + match &position { + PositionNoGoal::Field(field_position) => { + solboard.field[usize::from(field_position.column())] + .push(CardType::Special(self.card.clone())); + } + PositionNoGoal::Bunker { slot_index } => { + solboard.bunker[usize::from(*slot_index)] = + BunkerSlot::Stash(CardTypeNoHua::Special(self.card.clone())); + } + } + } + } + fn can_apply(&self, solboard: &Board) -> bool { + if self.destination_slot_index >= 3 { + return false; + } + let previous_slot_empty = solboard + .bunker + .iter() + .take(self.destination_slot_index.saturating_sub(1).into()) + .all(|x| { + if let BunkerSlot::Empty = x { + return true; + } else { + return false; + } + }); + if previous_slot_empty { + return false; + } + return true; + } + fn can_undo(&self, _solboard: &Board) -> bool { + return true; + } +} + +impl std::fmt::Display for DragonKill { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + return write!( + f, + "Kill {} to bunker #{} from {}, {}, {}, {}", + self.card, + self.destination_slot_index, + self.source[0], + self.source[1], + self.source[2], + self.source[3], + ); + } +} + +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] +pub struct Bunkerize { + pub card: CardTypeNoHua, + pub bunker_slot_index: u8, + pub field_position: FieldPosition, + pub to_bunker: bool, +} +impl Bunkerize { + fn can_move_to_bunker(&self, solboard: &Board) -> bool { + if self.field_position.row() + 1 + != solboard.field[usize::from(self.field_position.column())].len() as u8 + { + return false; + } + if self.card.add_hua() + != *solboard.field[usize::from(self.field_position.column())] + .last() + .unwrap() + { + return false; + } + if solboard.bunker[usize::from(self.bunker_slot_index)] != BunkerSlot::Empty { + return false; + } + return true; + } + fn move_to_bunker(&self, solboard: &mut Board) { + debug_assert!(self.can_move_to_bunker(solboard)); + solboard.field[usize::from(self.field_position.column())].pop(); + solboard.bunker[usize::from(self.bunker_slot_index)] = BunkerSlot::Stash(self.card.clone()); + } + fn can_move_from_bunker(&self, solboard: &Board) -> bool { + if solboard.bunker[usize::from(self.bunker_slot_index)] + != BunkerSlot::Stash(self.card.clone()) + { + return false; + } + if self.field_position.row() + != solboard.field[usize::from(self.field_position.column())].len() as u8 + { + return false; + } + return true; + } + fn move_from_bunker(&self, solboard: &mut Board) { + debug_assert!(self.can_move_from_bunker(solboard)); + solboard.field[usize::from(self.field_position.column())].push(self.card.add_hua()); + solboard.bunker[usize::from(self.bunker_slot_index)] = BunkerSlot::Empty; + } +} + +impl BoardApplication for Bunkerize { + fn apply(&self, solboard: &mut Board) { + if self.to_bunker { + self.move_to_bunker(solboard); + } else { + self.move_from_bunker(solboard); + } + } + fn undo(&self, solboard: &mut Board) { + if self.to_bunker { + self.move_from_bunker(solboard); + } else { + self.move_to_bunker(solboard); + } + } + fn can_apply(&self, solboard: &Board) -> bool { + if self.to_bunker { + return self.can_move_to_bunker(solboard); + } else { + return self.can_move_from_bunker(solboard); + } + } + fn can_undo(&self, solboard: &Board) -> bool { + if self.to_bunker { + return self.can_move_from_bunker(solboard); + } else { + return self.can_move_to_bunker(solboard); + } + } +} + +impl std::fmt::Display for Bunkerize { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + if self.to_bunker { + return write!( + f, + "Move {} from {} to bunker #{}", + self.card, self.field_position, self.bunker_slot_index, + ); + } else { + return write!( + f, + "Move {} from bunker #{} to {}", + self.card, self.bunker_slot_index, self.field_position, + ); + } + } +} + +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] +pub struct HuaKill { + pub field_position: FieldPosition, +} + +impl BoardApplication for HuaKill { + fn can_apply(&self, solboard: &Board) -> bool { + if solboard.field[usize::from(self.field_position.column())].last() + != Option::Some(&CardType::Hua) + { + return false; + } + if solboard.field[usize::from(self.field_position.column())].len() + != (self.field_position.row() + 1) as usize + { + return false; + } + return true; + } + fn apply(&self, solboard: &mut Board) { + debug_assert!(self.can_apply(solboard)); + solboard.field[usize::from(self.field_position.column())].pop(); + solboard.hua_set = true; + } + fn can_undo(&self, solboard: &Board) -> bool { + if solboard.field[usize::from(self.field_position.column())].len() + != self.field_position.row() as usize + { + return false; + } + return true; + } + fn undo(&self, solboard: &mut Board) { + debug_assert!(self.can_undo(solboard)); + solboard.field[usize::from(self.field_position.column())].push(CardType::Hua); + solboard.hua_set = false; + } +} +impl std::fmt::Display for HuaKill { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + return write!(f, "Kill hua from {}", self.field_position); + } +} +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] +pub enum All { + Bunkerize(Bunkerize), + DragonKill(DragonKill), + Goal(Goal), + HuaKill(HuaKill), + Move(super::Move), +} +impl std::fmt::Display for All { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + Self::Bunkerize(x) => return write!(f, "{}", x), + Self::DragonKill(x) => return write!(f, "{}", x), + Self::Goal(x) => return write!(f, "{}", x), + Self::HuaKill(x) => return write!(f, "{}", x), + Self::Move(x) => return write!(f, "{}", x), + } + } +} +impl All { + pub fn apply(&self, solboard: &mut Board) { + match self { + Self::HuaKill(obj) => { + obj.apply(solboard); + } + Self::DragonKill(obj) => { + obj.apply(solboard); + } + Self::Goal(obj) => { + obj.apply(solboard); + } + Self::Bunkerize(obj) => { + obj.apply(solboard); + } + Self::Move(obj) => obj.apply(solboard), + } + } + pub fn undo(&self, solboard: &mut Board) { + match self { + Self::HuaKill(obj) => { + obj.undo(solboard); + } + Self::DragonKill(obj) => { + obj.undo(solboard); + } + Self::Goal(obj) => { + obj.undo(solboard); + } + Self::Bunkerize(obj) => { + obj.undo(solboard); + } + Self::Move(obj) => obj.undo(solboard), + } + } +} diff --git a/solver-rs/lib/actions/src/lib.rs b/solver-rs/lib/actions/src/lib.rs new file mode 100644 index 0000000..0a65dac --- /dev/null +++ b/solver-rs/lib/actions/src/lib.rs @@ -0,0 +1,49 @@ +#![warn( + clippy::all, + clippy::restriction, + clippy::pedantic, + clippy::nursery, + clippy::cargo +)] +#![allow(clippy::cargo)] +// Style choices +#![allow( + clippy::missing_docs_in_private_items, + clippy::needless_return, + clippy::get_unwrap, + clippy::indexing_slicing, + clippy::explicit_iter_loop +)] +// Way too pedantic +#![allow(clippy::integer_arithmetic)] +// Useless +#![allow(clippy::missing_inline_in_public_items, clippy::missing_const_for_fn)] +// Useful for production +#![allow( + clippy::use_debug, + clippy::print_stdout, + clippy::dbg_macro, + clippy::panic +)] +// Useful for improving code robustness +#![allow( + clippy::cast_possible_truncation, + clippy::cast_possible_wrap, + clippy::option_unwrap_used, + clippy::option_expect_used, + clippy::as_conversions, + // clippy::result_unwrap_used, + // clippy::wildcard_enum_match_arm +)] +#![allow(clippy::trivially_copy_pass_by_ref)] +#![allow(dead_code)] +mod base; +pub use base::*; + +mod move_action; +pub use move_action::*; + +#[cfg(test)] +mod tests; + +pub mod possibilities; \ No newline at end of file diff --git a/solver-rs/lib/actions/src/move_action.rs b/solver-rs/lib/actions/src/move_action.rs new file mode 100644 index 0000000..f407028 --- /dev/null +++ b/solver-rs/lib/actions/src/move_action.rs @@ -0,0 +1,178 @@ +use board::{Board, CardType, FieldPosition, NumberCard, NumberCardColor}; +use serde::{Deserialize, Serialize}; + +const COLOR_SEQUENCE: [NumberCardColor; 3] = [ + NumberCardColor::Red, + NumberCardColor::Green, + NumberCardColor::Black, +]; + +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] +pub struct Move { + start_card: CardType, + stack_len: u8, + pattern: u8, + pub source: FieldPosition, + pub destination: FieldPosition, +} + +impl Move { + #[must_use] + fn alternate_card(bottom_suit: &NumberCardColor, bit: u8) -> NumberCardColor { + let pos = COLOR_SEQUENCE + .iter() + .position(|x| return x == bottom_suit) + .unwrap(); + let shift_value = if bit == 0 { 0 } else { 1 }; + return COLOR_SEQUENCE[(pos + shift_value + 1) % 3].clone(); + } + + #[must_use] + fn bit_card(last_card: &board::NumberCardColor, current_card: &board::NumberCardColor) -> u8 { + let last_pos = COLOR_SEQUENCE + .iter() + .position(|x| return x == last_card) + .unwrap(); + let current_pos = COLOR_SEQUENCE + .iter() + .position(|x| return x == current_card) + .unwrap(); + if (last_pos + 1) % 3 == current_pos { + return 0; + } else { + return 1; + } + } + #[must_use] + pub fn cards(&self) -> Vec { + if let CardType::Number(NumberCard { value, .. }) = self.start_card { + let mut result = Vec::with_capacity(usize::from(self.stack_len)); + result.push(self.start_card.clone()); + for index in 1..self.stack_len { + let new_color = if let board::CardType::Number(board::NumberCard { + suit: last_suit, + .. + }) = result.last().unwrap() + { + Self::alternate_card(last_suit, self.pattern & (1 << (index - 1))) + } else { + panic!(""); + }; + result.push(board::CardType::Number(board::NumberCard { + suit: new_color, + value: value - index, + })); + } + return result; + } else { + return vec![self.start_card.clone()]; + } + } + + #[must_use] + pub fn stack_len(&self) -> u8 { + return self.stack_len; + } + + #[must_use] + pub fn new<'a>( + source: FieldPosition, + destination: FieldPosition, + cards: &'a [board::CardType], + ) -> Self { + let mut pattern: u8 = 0; + let numbercard_filter = |card: &'a CardType| -> Option<&'a NumberCard> { + if let board::CardType::Number(numbercard) = card { + return Option::Some(numbercard); + } else { + return Option::None; + } + }; + for (index, (last_card, card)) in (0_u8..).zip( + cards + .iter() + .filter_map(numbercard_filter) + .zip(cards.iter().skip(1).filter_map(numbercard_filter)), + ) { + pattern |= Self::bit_card(&last_card.suit, &card.suit) << index; + debug_assert_eq!(card.value + 1, last_card.value); + } + + return Self { + source, + destination, + start_card: cards[0].clone(), + stack_len: cards.len() as u8, + pattern, + }; + } +} + +impl super::BoardApplication for Move { + fn apply(&self, solboard: &mut Board) { + solboard.field[usize::from(self.source.column())].truncate( + solboard.field[usize::from(self.source.column())].len() - usize::from(self.stack_len()), + ); + solboard.field[usize::from(self.destination.column())].append(&mut self.cards()); + } + + fn undo(&self, solboard: &mut Board) { + solboard.field[usize::from(self.destination.column())].truncate( + solboard.field[usize::from(self.destination.column())].len() + - usize::from(self.stack_len()), + ); + solboard.field[usize::from(self.source.column())].append(&mut self.cards()); + } + + #[must_use] + fn can_apply(&self, _solboard: &Board) -> bool { + return true; + } + + #[must_use] + fn can_undo(&self, _solboard: &Board) -> bool { + return true; + } +} + +impl std::fmt::Display for Move { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + let card_name = if self.stack_len() == 1 { + format!("{}", self.cards()[0]) + } else { + format!("{} cards", self.stack_len()) + }; + return write!( + f, + "Move {} from {} to {}", + card_name, self.source, self.destination + ); + } +} + +#[test] +fn move_storage() { + let card_stack = vec![ + board::CardType::Number(NumberCard { + value: 5, + suit: board::NumberCardColor::Red, + }), + board::CardType::Number(NumberCard { + value: 4, + suit: board::NumberCardColor::Black, + }), + board::CardType::Number(NumberCard { + value: 3, + suit: board::NumberCardColor::Green, + }), + ]; + let source = FieldPosition::new(0, 0); + let destination = FieldPosition::new(0, 1); + let my_move = Move::new(source.clone(), destination.clone(), &card_stack); + assert_eq!(my_move.cards(), card_stack); + let my_move = Move::new(source, destination, &card_stack[0..1]); + assert_eq!( + my_move.cards().iter().collect::>(), + card_stack.iter().take(1).collect::>() + ) +} diff --git a/solver-rs/lib/actions/src/possibilities.rs b/solver-rs/lib/actions/src/possibilities.rs new file mode 100644 index 0000000..596e194 --- /dev/null +++ b/solver-rs/lib/actions/src/possibilities.rs @@ -0,0 +1,373 @@ +use board::{ + Board, BunkerSlot, CardType, CardTypeNoHua, FieldPosition, NumberCard, NumberCardColor, + PositionNoGoal, SpecialCardType, +}; + +#[must_use] +pub fn bunkerize_actions(solboard: &Board) -> Vec { + let first_empty_bunker_index = solboard.bunker.iter().position(|x| match x { + BunkerSlot::Empty => return true, + _ => return false, + }); + if let Option::Some(first_empty_bunker_index) = first_empty_bunker_index { + return solboard + .field + .iter() + .enumerate() + .filter_map(|(index, row)| { + return row + .last() + .filter(|card| { + if let CardType::Hua = card { + return false; + } else { + return true; + } + }) + .map(|card| { + let field_position = FieldPosition::new(index as u8, (row.len() - 1) as u8); + return crate::All::Bunkerize(crate::Bunkerize { + field_position, + card: card.remove_hua(), + bunker_slot_index: first_empty_bunker_index as u8, + to_bunker: true, + }); + }); + }) + .collect(); + } + return Vec::new(); +} + +fn card_fits(source: &NumberCard, dest: &NumberCard) -> bool { + return (source.suit != dest.suit) && (source.value + 1 == dest.value); +} + +fn fitting_field_number_position(card: &NumberCard, board: &Board) -> Option { + return board.field.iter().enumerate().find_map(|(index, row)| { + if let Option::Some(CardType::Number(top_card)) = row.last() { + if card_fits(card, top_card) { + return Option::Some(FieldPosition::new(index as u8, (row.len()) as u8)); + } + } + return Option::None; + }); +} + +fn fitting_field_positions(card: &CardType, board: &Board) -> Vec { + let mut result = Vec::new(); + if let CardType::Number(card) = card { + if let Option::Some(position) = fitting_field_number_position(card, board) { + result.push(position); + } + } + if let Option::Some(position) = + (0_u8..) + .zip(board.field.iter()) + .find_map(|(column_index, slot)| { + if slot.is_empty() { + return Option::Some(FieldPosition::new(column_index, 0)); + } else { + return Option::None; + } + }) + { + result.push(position) + } + return result; +} + +#[must_use] +pub fn debunkerize_actions(solboard: &Board) -> Vec { + let number_matching_cards = + (0_u8..) + .zip(solboard.bunker.iter()) + .filter_map(|(bunker_slot_index, slot)| { + if let BunkerSlot::Stash(CardTypeNoHua::Number(card)) = slot { + return fitting_field_number_position(card, solboard).map(|field_position| { + return crate::All::Bunkerize(crate::Bunkerize { + card: CardTypeNoHua::Number(card.clone()), + field_position, + bunker_slot_index, + to_bunker: false, + }); + }); + } else { + return Option::None; + } + }); + let empty_slot = solboard + .field + .iter() + .position(|row| return row.is_empty()) + .map(|column_index| { + return FieldPosition::new(column_index as u8, 0); + }); + if let Option::Some(field_position) = empty_slot { + let empty_slot_cards = + (0_u8..) + .zip(solboard.bunker.iter()) + .filter_map(|(bunker_slot_index, slot)| { + if let BunkerSlot::Stash(card) = slot { + let result = crate::Bunkerize { + card: card.clone(), + bunker_slot_index, + field_position, + to_bunker: false, + }; + return Option::Some(crate::All::Bunkerize(result)); + } else { + return Option::None; + } + }); + + return number_matching_cards.chain(empty_slot_cards).collect(); + } else { + return number_matching_cards.collect(); + } +} + +struct DragonTracker { + dragons: [(u8, [PositionNoGoal; 4]); 3], +} +impl DragonTracker { + fn new() -> Self { + return Self { + dragons: [(0, [PositionNoGoal::Bunker { slot_index: 0 }; 4]); 3], + }; + } + + fn dragon_to_id(dragon: &SpecialCardType) -> u8 { + return match dragon { + SpecialCardType::Zhong => 0, + SpecialCardType::Bai => 1, + SpecialCardType::Fa => 2, + }; + } + fn id_to_dragon(id: u8) -> SpecialCardType { + return match id { + 0 => SpecialCardType::Zhong, + 1 => SpecialCardType::Bai, + 2 => SpecialCardType::Fa, + _ => panic!("Dragon id too high"), + }; + } + + fn push(&mut self, dragon: &SpecialCardType, position: PositionNoGoal) { + let (ref mut count, ref mut cell) = self.dragons[usize::from(Self::dragon_to_id(dragon))]; + cell[usize::from(*count)] = position; + *count += 1; + } + + fn found_dragons(&self) -> impl Iterator { + return (0_u8..) + .zip(self.dragons.iter()) + .filter_map(|(index, (count, positions))| { + if *count == 4 { + return Option::Some((Self::id_to_dragon(index), positions)); + } else { + return Option::None; + } + }); + } +} + +#[must_use] +pub fn dragonkill_actions(solboard: &Board) -> Vec { + let mut dragon_position = DragonTracker::new(); + for (position, card) in solboard.movable_cards() { + if let CardType::Special(card) = card { + dragon_position.push(&card, position); + } + } + let mut result: Vec = Vec::new(); + for (card_type, positions) in dragon_position.found_dragons() { + let dragon_destination = solboard.bunker.iter().position(|x| { + return match x { + BunkerSlot::Empty => true, + BunkerSlot::Stash(CardTypeNoHua::Special(special_card_type)) => { + special_card_type == &card_type + } + _ => false, + }; + }); + if let Option::Some(dragon_destination) = dragon_destination { + let mut my_positions: [PositionNoGoal; 4] = + [PositionNoGoal::Bunker { slot_index: 0 }; 4]; + my_positions.clone_from_slice(positions); + result.push(crate::All::DragonKill(crate::DragonKill { + card: card_type.clone(), + source: my_positions, + destination_slot_index: dragon_destination as u8, + })); + } + } + + return result; +} + +fn get_max_stack_count(board: &Board) -> [u8; 8] { + let mut result = [0; 8]; + for (index, row) in result.iter_mut().zip(&board.field) { + let row_iterator = row.iter().rev(); + let mut next_row_iterator = row.iter().rev(); + if next_row_iterator.next().is_none() { + *index = 0; + continue; + } + *index = (row_iterator + .zip(next_row_iterator) + .take_while(|(card, bottom_card)| { + if let (CardType::Number(card), CardType::Number(bottom_card)) = (card, bottom_card) + { + return card_fits(card, bottom_card); + } else { + return false; + } + }) + .count() + + 1) as u8; + } + return result; +} + +#[must_use] +pub fn field_move_actions(solboard: &Board) -> Vec { + let max_stack_counts: [u8; 8] = get_max_stack_count(solboard); + let required_size: u8 = max_stack_counts.iter().cloned().sum(); + let mut result = Vec::with_capacity(usize::from(required_size)); + for ((column_index, row), stack_size) in (0_u8..) + .zip(solboard.field.iter()) + .zip(max_stack_counts.iter()) + .filter(|(_, size)| return **size > 0) + { + for row_index in (row.len() - usize::from(*stack_size)) as u8..(row.len()) as u8 { + let my_stack = &row + .get(usize::from(row_index)..row.len()) + .expect("Slicing failed"); + for position in fitting_field_positions( + my_stack + .first() + .expect("Stack should at least have one entry"), + solboard, + ) { + result.push(crate::All::Move(crate::Move::new( + FieldPosition::new(column_index, row_index), + position, + my_stack, + ))); + } + } + } + return result; +} + +#[must_use] +pub fn goal_move_actions(solboard: &Board) -> Vec { + let suit_to_id = |suit: &NumberCardColor| -> u8 { + return match suit { + NumberCardColor::Red => 0, + NumberCardColor::Green => 1, + NumberCardColor::Black => 2, + }; + }; + let first_empty_goal_slot_index = (0_u8..) + .zip(solboard.goal.iter()) + .find_map(|(index, card)| { + if card.is_none() { + return Option::Some(index); + } else { + return Option::None; + } + }) + .unwrap_or(3); + let mut goal_desired_pos = [(1_u8, first_empty_goal_slot_index); 3]; + + for (slot_id, card) in (0_u8..).zip(solboard.goal.iter()) { + match card { + Option::Some(NumberCard { value, suit }) => { + goal_desired_pos[usize::from(suit_to_id(suit))] = (*value + 1, slot_id); + } + Option::None => {} + }; + } + let mut result = Vec::::new(); + for (position, card) in solboard.movable_cards() { + if let CardType::Number(card) = card { + if goal_desired_pos[usize::from(suit_to_id(&card.suit))].0 == card.value { + result.push(crate::All::Goal(crate::Goal { + card: card.clone(), + source: position, + goal_slot_index: goal_desired_pos[usize::from(suit_to_id(&card.suit))].1, + })); + } + } + } + return result; +} + +#[must_use] +pub fn huakill_actions(solboard: &Board) -> Vec { + for (slot_id, field_column) in (0_u8..).zip(solboard.field.iter()) { + if let Option::Some(CardType::Hua) = field_column.last() { + return vec![crate::All::HuaKill(crate::HuaKill { + field_position: FieldPosition::new(slot_id, (field_column.len() - 1) as u8), + })]; + } + } + return Vec::new(); +} + +#[must_use] +pub fn all_actions(solboard: &Board) -> Vec { + return [ + &huakill_actions(solboard)[..], + &dragonkill_actions(solboard)[..], + &goal_move_actions(solboard)[..], + &debunkerize_actions(solboard)[..], + &field_move_actions(solboard)[..], + &bunkerize_actions(solboard)[..], + ] + .concat(); +} + +#[must_use] +pub fn filter_actions(solboard: &Board) -> Vec { + let action_list = all_actions(solboard); + let huakill_action = action_list.iter().find(|x| { + if let crate::All::HuaKill(_) = x { + return true; + } else { + return false; + } + }); + if let Option::Some(action) = huakill_action { + return vec![action.clone()]; + } + let mut goal_actions = action_list.iter().filter_map(|x| { + if let crate::All::Goal(x) = x { + return Option::Some(x); + } else { + return Option::None; + } + }); + let minimum_goal = solboard + .goal + .iter() + .map(|x| match x { + Option::None => return 0, + Option::Some(card) => return card.value, + }) + .min() + .unwrap(); + if let Option::Some(minimum_goal_action) = goal_actions + .by_ref() + .min_by(|x, y| return x.card.value.cmp(&y.card.value)) + { + if minimum_goal_action.card.value <= minimum_goal + 1 { + return vec![crate::All::Goal(minimum_goal_action.clone())]; + } + } + + return action_list.to_vec(); +} diff --git a/solver-rs/lib/actions/src/tests.rs b/solver-rs/lib/actions/src/tests.rs new file mode 100644 index 0000000..cf5c132 --- /dev/null +++ b/solver-rs/lib/actions/src/tests.rs @@ -0,0 +1,39 @@ +use crate::possibilities::{all_actions, bunkerize_actions, dragonkill_actions}; +use board::{BunkerSlot, CardTypeNoHua, SpecialCardType}; +#[test] +pub fn dragonkill_test() -> Result<(), Box> { + let mut x = board::load_test_board!("specific/dragonkill.json")?; + assert_eq!(dragonkill_actions(&x).len(), 1); + x.field[3].pop(); + x.bunker[2] = BunkerSlot::Stash(CardTypeNoHua::Special(SpecialCardType::Zhong)); + assert_eq!(dragonkill_actions(&x).len(), 1); + return Result::Ok(()); +} + +#[test] +pub fn bunkerize_test() -> Result<(), Box> { + let x = board::load_test_board!("specific/dragonkill.json")?; + assert_eq!(bunkerize_actions(&x).len(), 5); + return Result::Ok(()); +} + +#[test] +pub fn all_actions_test() -> Result<(), Box> { + let x = board::load_test_board!("specific/dragonkill.json")?; + let possible_actions = all_actions(&x); + assert_eq!(possible_actions.len(), 12); + assert_eq!( + possible_actions.iter().fold([0, 0, 0, 0, 0], |mut sum, x| { + match x { + crate::All::Bunkerize(_) => sum[0] += 1, + crate::All::Move(_) => sum[1] += 1, + crate::All::Goal(_) => sum[2] += 1, + crate::All::DragonKill(_) => sum[3] += 1, + _ => sum[4] += 1, + } + return sum; + }), + [5, 5, 1, 1, 0] + ); + return Result::Ok(()); +} diff --git a/solver-rs/lib/board/Cargo.toml b/solver-rs/lib/board/Cargo.toml new file mode 100644 index 0000000..1b887cb --- /dev/null +++ b/solver-rs/lib/board/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "board" +version = "0.1.0" +authors = ["Lukas Wölfer "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +serde = {version="1.0.105",features=["derive"]} +serde_json = "1.0" +enum-iterator = "0.6.0" diff --git a/solver-rs/lib/board/fuzz/.gitignore b/solver-rs/lib/board/fuzz/.gitignore new file mode 100644 index 0000000..572e03b --- /dev/null +++ b/solver-rs/lib/board/fuzz/.gitignore @@ -0,0 +1,4 @@ + +target +corpus +artifacts diff --git a/solver-rs/lib/board/fuzz/Cargo.lock b/solver-rs/lib/board/fuzz/Cargo.lock new file mode 100644 index 0000000..ef26e91 --- /dev/null +++ b/solver-rs/lib/board/fuzz/Cargo.lock @@ -0,0 +1,216 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "arbitrary" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75153c95fdedd7db9732dfbfc3702324a1627eec91ba56e37cd0ac78314ab2ed" + +[[package]] +name = "board" +version = "0.1.0" +dependencies = [ + "enum-iterator", + "serde", + "serde_json", +] + +[[package]] +name = "board-fuzz" +version = "0.0.0" +dependencies = [ + "board", + "enum-iterator", + "libfuzzer-sys", + "rand", +] + +[[package]] +name = "cc" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "enum-iterator" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c79a6321a1197d7730510c7e3f6cb80432dfefecb32426de8cea0aa19b4bb8d7" +dependencies = [ + "enum-iterator-derive", +] + +[[package]] +name = "enum-iterator-derive" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e94aa31f7c0dc764f57896dc615ddd76fc13b0d5dca7eb6cc5e018a5a09ec06" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "getrandom" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "itoa" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" + +[[package]] +name = "libc" +version = "0.2.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0" + +[[package]] +name = "libfuzzer-sys" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d718794b8e23533b9069bd2c4597d69e41cc7ab1c02700a502971aca0cdcf24" +dependencies = [ + "arbitrary", + "cc", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" + +[[package]] +name = "proc-macro2" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df246d292ff63439fea9bc8c0a270bed0e390d5ebd4db4ba15aba81111b5abe3" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom", + "libc", + "rand_chacha", + "rand_core", + "rand_hc", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core", +] + +[[package]] +name = "ryu" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "535622e6be132bccd223f4bb2b8ac8d53cda3c7a6394944d3b2b33fb974f9d76" + +[[package]] +name = "serde" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36df6ac6412072f67cf767ebbde4133a5b2e88e76dc6187fa7104cd16f783399" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e549e3abf4fb8621bd1609f11dfc9f5e50320802273b12f3811a67e6716ea6c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78a7a12c167809363ec3bd7329fc0a3369056996de43c4b37ef3cd54a6ce4867" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "syn" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0df0eb663f387145cab623dea85b09c2c5b4b0aef44e945d928e682fce71bb03" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "unicode-xid" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" diff --git a/solver-rs/lib/board/fuzz/Cargo.toml b/solver-rs/lib/board/fuzz/Cargo.toml new file mode 100644 index 0000000..9b13a18 --- /dev/null +++ b/solver-rs/lib/board/fuzz/Cargo.toml @@ -0,0 +1,26 @@ + +[package] +name = "board-fuzz" +version = "0.0.0" +authors = ["Automatically generated"] +publish = false +edition = "2018" + +[package.metadata] +cargo-fuzz = true + +[dependencies] +libfuzzer-sys = "0.3" +rand = "*" +enum-iterator = "*" + +[dependencies.board] +path = ".." + +# Prevent this from interfering with workspaces +[workspace] +members = ["."] + +[[bin]] +name = "fuzz_target_1" +path = "fuzz_targets/fuzz_target_1.rs" diff --git a/solver-rs/lib/board/fuzz/fuzz_targets/fuzz_target_1.rs b/solver-rs/lib/board/fuzz/fuzz_targets/fuzz_target_1.rs new file mode 100644 index 0000000..91863b0 --- /dev/null +++ b/solver-rs/lib/board/fuzz/fuzz_targets/fuzz_target_1.rs @@ -0,0 +1,127 @@ +#![no_main] +use libfuzzer_sys::fuzz_target; + +use board::{Board, CardType}; +use enum_iterator::IntoEnumIterator; +use rand::seq::SliceRandom; + +struct RandomBytes<'a> { + data: &'a [u8], + index: usize, +} + +impl<'a> rand::RngCore for RandomBytes<'a> { + fn next_u32(&mut self) -> u32 { + if let Option::Some(x) = self.data.get(self.index..self.index + 4) { + self.index += 4; + return (u32::from(x[3]) << 24) + | (u32::from(x[2]) << 16) + | (u32::from(x[1]) << 8) + | u32::from(x[0]); + } else { + self.index = self.data.len(); + return 0; + } + } + fn next_u64(&mut self) -> u64 { + return u64::from(self.next_u32()) << 32 | u64::from(self.next_u32()); + } + fn fill_bytes(&mut self, dest: &mut [u8]) { + if (self.index >= self.data.len()) || (dest.len() > self.data.len() - self.index) { + for cell in dest.iter_mut() { + *cell = 0; + } + } + if dest.len() < self.data.len() - self.index { + dest.clone_from_slice(&self.data[self.index..self.index + dest.len()]); + self.index += dest.len() + } + } + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand::Error> { + self.fill_bytes(dest); + return Result::Ok(()); + } +} + +fn correct_board_permutation(data: &[u8]) -> Board { + if let Option::Some(remove_info) = data.get(0..2) { + let remove_info: u16 = u16::from(remove_info[1]) << 8 | u16::from(remove_info[0]); + let mut result = Board::default(); + let mut whole_vec = Vec::::new(); + if remove_info & 1 == 1 { + result.hua_set = true; + } else { + whole_vec.push(CardType::Hua); + result.hua_set = false; + } + for (index, card) in (1_u8..).zip(board::SpecialCardType::into_enum_iter()) { + if remove_info & (1 << index) == 0 { + result.bunker[usize::from(index - 1)] = + board::BunkerSlot::Blocked(Option::Some(card.clone())); + } else { + whole_vec.push(CardType::Special(card.clone())); + whole_vec.push(CardType::Special(card.clone())); + whole_vec.push(CardType::Special(card.clone())); + whole_vec.push(CardType::Special(card.clone())); + result.bunker[usize::from(index - 1)] = board::BunkerSlot::Empty; + } + } + for (index, suit) in (4_u8..) + .step_by(4) + .zip(board::NumberCardColor::into_enum_iter()) + { + let value = (((remove_info >> index) & 0b1111) % 10) as u8; + let slot_index = usize::from((index - 4) / 4); + if value == 0 { + result.goal[slot_index] = Option::None; + } else { + result.goal[slot_index] = Option::Some(board::NumberCard { + value, + suit: suit.clone(), + }); + } + for value in (value + 1)..10 { + whole_vec.push(board::CardType::Number(board::NumberCard { + value, + suit: suit.clone(), + })); + } + } + whole_vec.shuffle(&mut RandomBytes { data, index: 2 }); + for ((index_start, index_end), slot) in (0..) + .step_by(8) + .zip((8..).step_by(8)) + .zip(result.field.iter_mut()) + { + if let Option::Some(tasty_slice) = whole_vec.get(index_start..index_end) { + slot.extend_from_slice(tasty_slice); + } else if let Option::Some(tasty_slice) = whole_vec.get(index_start..) { + slot.extend_from_slice(tasty_slice); + break; + } else { + break; + } + } + return result; + } else { + return Board::default(); + } +} + +fuzz_target!(|data: &[u8]| { + if data.len() == 0 { + return; + } + let x = correct_board_permutation(&data[1..]); + assert_eq!(x.check(), Result::Ok(())); + if let Option::Some(action) = board::possibilities::all_actions(&x).choose(&mut RandomBytes { + data: &data[0..1], + index: 0, + }) { + let mut action_board = x.clone(); + action.apply(&mut action_board); + assert_ne!(action_board, x); + action.undo(&mut action_board); + assert_eq!(action_board, x); + } +}); diff --git a/solver-rs/lib/board/src/board_class.rs b/solver-rs/lib/board/src/board_class.rs new file mode 100644 index 0000000..6410a38 --- /dev/null +++ b/solver-rs/lib/board/src/board_class.rs @@ -0,0 +1,403 @@ +use crate::{ + BunkerSlot, CardType, CardTypeNoHua, FieldPosition, NumberCard, NumberCardColor, + PositionNoGoal, SpecialCardType, +}; +use enum_iterator::IntoEnumIterator; +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; +use std::fs::File; +use std::io::BufReader; +use std::path::Path; + +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +pub enum Error { + CardMissing(CardType), + CardDouble(CardType), + GoalTooHigh(NumberCard), + ErraneousCard(NumberCard), +} + +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Hash)] +pub struct Board { + pub field: [Vec; 8], + pub goal: [Option; 3], + pub hua_set: bool, + pub bunker: [BunkerSlot; 3], +} + +impl Default for Board { + fn default() -> Self { + return Self { + field: [ + Vec::new(), + Vec::new(), + Vec::new(), + Vec::new(), + Vec::new(), + Vec::new(), + Vec::new(), + Vec::new(), + ], + goal: [ + Option::Some(NumberCard { + value: 9, + suit: NumberCardColor::Black, + }), + Option::Some(NumberCard { + value: 9, + suit: NumberCardColor::Red, + }), + Option::Some(NumberCard { + value: 9, + suit: NumberCardColor::Green, + }), + ], + hua_set: false, + bunker: [ + BunkerSlot::Blocked(Option::Some(SpecialCardType::Bai)), + BunkerSlot::Blocked(Option::Some(SpecialCardType::Zhong)), + BunkerSlot::Blocked(Option::Some(SpecialCardType::Fa)), + ], + }; + } +} +pub struct BoardEqHash([u8; 32]); +impl PartialEq for BoardEqHash { + fn eq(&self, other: &Self) -> bool { + return self + .0 + .iter() + .zip(other.0.iter()) + .all(|(this_cell, other_cell)| return this_cell == other_cell); + } +} +impl Eq for BoardEqHash {} + +impl std::hash::Hash for BoardEqHash { + fn hash(&self, state: &mut H) { + state.write(&self.0); + } +} +impl std::str::FromStr for Board { + type Err = serde_json::error::Error; + fn from_str(json_string: &str) -> Result { + //! # Errors + //! Will return `io::Result::Err` when the path cannot be found, + //! and `Result::Err` when the json in the file is incorrect + return serde_json::from_str::(json_string); + } +} + +struct BitSquasher<'a> { + sink: &'a mut [u8], + byte: usize, + bit: u8, +} + +impl<'a> BitSquasher<'a> { + pub fn new(sink: &'a mut [u8]) -> Self { + return BitSquasher { + sink, + byte: 0, + bit: 0, + }; + } + pub fn squash(&mut self, input: u8, count: u8) { + debug_assert!(count <= 8); + debug_assert!(count > 0); + self.sink[self.byte] |= input << self.bit; + if (8 - self.bit) < count { + self.sink[self.byte + 1] |= input >> (8 - self.bit); + } + self.bit += count; + self.byte += usize::from(self.bit / 8); + self.bit %= 8; + } +} + +#[test] +fn bit_squasher_test() { + let mut buffer: [u8; 4] = Default::default(); + + let mut squasher = BitSquasher::new(&mut buffer); + squasher.squash(0b101, 3); + squasher.squash(0b1111000, 7); + squasher.squash(0b11001100, 8); + squasher.squash(0b101010, 6); + + assert_eq!(buffer, [0b11000101, 0b00110011, 0b10101011, 0]); +} + +impl Board { + pub fn from_file(path: &Path) -> Result> { + //! # Errors + //! Will return `io::Result::Err` when the path cannot be found, + //! and `Result::Err` when the json in the file is incorrect + let f = File::open(path)?; + let reader = BufReader::new(f); + let x: Self = serde_json::from_reader(reader)?; + return Result::Ok(x); + } + + #[must_use] + pub fn goal_value(&self, suit: &NumberCardColor) -> u8 { + return self + .goal + .iter() + .filter_map(|card| return card.clone()) + .find_map(|card| { + if &card.suit == suit { + return Option::Some(card.value); + } else { + return Option::None; + } + }) + .unwrap_or(0); + } + #[must_use] + pub fn equivalence_hash(&self) -> BoardEqHash { + // up to 40 cards on the field + // 8 empty card represents end of slot + // 3 bunker + // If hua in field -> hua not set, does not need representation + // We can skip goal, as the value of the card in the goal + // is the highest value missing from the board; + let mut result = [0_u8; 32]; + let mut squasher = BitSquasher::new(&mut result); + + let mut field_lengths: [usize; 8] = Default::default(); + for (index, cell) in field_lengths.iter_mut().enumerate() { + *cell = index; + } + field_lengths.sort_unstable_by(|left_index, right_index| { + return self.field[*left_index].cmp(&self.field[*right_index]); + }); + let sorted_iter = field_lengths.iter().map(|index| return &self.field[*index]); + + for slot in sorted_iter { + let slot_size = slot.len(); + debug_assert!(slot.len() < 16); + squasher.squash(slot_size as u8, 4); + for cell in slot { + let cell_byte = cell.to_byte(); + debug_assert!(cell_byte < 32); + squasher.squash(cell_byte, 5); + } + } + let mut sorted_bunker = self.bunker.clone(); + sorted_bunker.sort_unstable(); + for slot in sorted_bunker.iter() { + let bunker_byte = match slot { + BunkerSlot::Empty => 0, + BunkerSlot::Stash(card) => card.add_hua().to_byte(), + BunkerSlot::Blocked(Option::Some(card)) => { + CardType::Special(card.clone()).to_byte() | (1 << 5) + } + BunkerSlot::Blocked(Option::None) => (1 << 5), + }; + debug_assert!(bunker_byte < 64); + squasher.squash(bunker_byte, 6); + } + return BoardEqHash(result); + } + pub fn movable_cards<'a>(&'a self) -> impl Iterator + 'a { + let bunker_iterator = (0_u8..) + .zip(self.bunker.iter()) + .filter_map(|(index, card)| { + let pos = PositionNoGoal::Bunker { slot_index: index }; + let ret_card = match card { + BunkerSlot::Stash(CardTypeNoHua::Special(card)) => { + Option::Some(CardType::Special(card.clone())) + } + BunkerSlot::Stash(CardTypeNoHua::Number(card)) => { + Option::Some(CardType::Number(card.clone())) + } + _ => Option::None, + }; + return ret_card.map(|card| return (pos, card)); + }); + let field_iterator = (0_u8..) + .zip(self.field.iter()) + .filter_map(|(column_index, row)| { + return row.last().map(|ret_card| { + let pos = PositionNoGoal::Field(FieldPosition::new( + column_index, + (row.len() - 1) as u8, + )); + return (pos, ret_card.clone()); + }); + }); + let result = bunker_iterator.chain(field_iterator); + return result; + } + + fn handle_number_card( + card: &NumberCard, + number_card_map: &mut HashMap, + ) -> Result<(), Error> { + if card.value > 9 || card.value < 1 { + return Result::Err(Error::ErraneousCard(card.clone())); + } + if *number_card_map + .get_mut(&card.suit) + .unwrap() + .get(usize::from(card.value - 1)) + .unwrap() + { + return Result::Err(Error::CardDouble(CardType::Number(card.clone()))); + } + *number_card_map + .get_mut(&card.suit) + .unwrap() + .get_mut(usize::from(card.value - 1)) + .unwrap() = true; + return Result::Ok(()); + } + fn handle_special_card( + card: &SpecialCardType, + special_card_map: &mut HashMap, + ) -> Result<(), Error> { + let card_slot = special_card_map.entry(card.clone()).or_insert(0); + if *card_slot > 4 { + return Result::Err(Error::CardDouble(CardType::Special(card.clone()))); + } + *card_slot += 1; + return Result::Ok(()); + } + + pub fn check(&self) -> Result<(), Error> { + //! # Errors + //! + //! Returns the error in the board + let mut special_card_map: HashMap = HashMap::new(); + let mut number_card_map: HashMap = HashMap::new(); + let mut unknown_blocked_count: u8 = 0; + for color in NumberCardColor::into_enum_iter() { + number_card_map.insert(color.clone(), [false; 9]); + } + for special_card_type in SpecialCardType::into_enum_iter() { + special_card_map.insert(special_card_type.clone(), 0); + } + let mut hua_exists: bool = self.hua_set; + + for field_row in &self.field { + for cell in field_row.iter() { + match cell { + CardType::Number(number_card) => { + Self::handle_number_card(number_card, &mut number_card_map)?; + } + CardType::Special(card_type) => { + Self::handle_special_card(card_type, &mut special_card_map)?; + } + CardType::Hua => { + if hua_exists { + return Result::Err(Error::CardDouble(CardType::Hua)); + } else { + hua_exists = true + } + } + } + } + } + + for bunker_cell in &self.bunker { + match bunker_cell { + BunkerSlot::Blocked(Option::None) => unknown_blocked_count += 1, + BunkerSlot::Blocked(Option::Some(special_card_type)) => { + for _ in 0..4 { + Self::handle_special_card(special_card_type, &mut special_card_map)?; + } + } + BunkerSlot::Stash(CardTypeNoHua::Special(special_card_type)) => { + Self::handle_special_card(special_card_type, &mut special_card_map)?; + } + BunkerSlot::Stash(CardTypeNoHua::Number(number_card)) => { + Self::handle_number_card(number_card, &mut number_card_map)?; + } + BunkerSlot::Empty => {} + } + } + + for goal_cell in &self.goal { + if let Some(NumberCard { suit, value }) = goal_cell { + let color_slice = number_card_map.get_mut(suit).unwrap(); + for i in 0..*value { + if *color_slice.get(usize::from(i)).unwrap() { + return Result::Err(Error::GoalTooHigh(NumberCard { + suit: suit.clone(), + value: *value, + })); + } + *color_slice.get_mut(usize::from(i)).unwrap() = true; + } + } + } + for (card_type, count) in &special_card_map { + if *count != 4 { + if unknown_blocked_count == 0 { + return Result::Err(Error::CardMissing(CardType::Special(card_type.clone()))); + } + unknown_blocked_count -= 1; + } + } + for (card_type, value_array) in &number_card_map { + for (index, value_hit) in (0_u8..).zip(value_array.iter()) { + if !*value_hit { + return Result::Err(Error::CardMissing(CardType::Number(NumberCard { + suit: card_type.clone(), + value: (index + 1), + }))); + } + } + } + return Result::Ok(()); + } + + #[must_use] + pub fn solved(&self) -> bool { + for row in &self.field { + if !row.is_empty() { + return false; + } + } + for slot in &self.bunker { + if let BunkerSlot::Blocked(_) = slot { + } else { + return false; + } + } + if !self.hua_set { + return false; + } + + for goal_slot in &self.goal { + if goal_slot.is_none() { + return false; + } + } + for color in NumberCardColor::into_enum_iter() { + let color_position = self.goal.iter().position(|goal_card| { + return goal_card + .as_ref() + .expect("We already checked that every goal slot is not None") + .suit + == color; + }); + if color_position.is_none() { + return false; + } + } + + for card in &self.goal { + if card + .as_ref() + .expect("We already checked that every goal slot is not None") + .value + != 9 + { + return false; + } + } + return true; + } +} diff --git a/solver-rs/lib/board/src/cards.rs b/solver-rs/lib/board/src/cards.rs new file mode 100644 index 0000000..9772cec --- /dev/null +++ b/solver-rs/lib/board/src/cards.rs @@ -0,0 +1,118 @@ +use enum_iterator::IntoEnumIterator; +use serde::{Deserialize, Serialize}; +use std::fmt::Display; +#[derive( + Serialize, Deserialize, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Clone, IntoEnumIterator, +)] +pub enum SpecialCardType { + Zhong, + Bai, + Fa, +} + +impl Display for SpecialCardType { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + return write!(f, "{:#?}", self); + } +} + +#[derive( + Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, IntoEnumIterator, +)] +pub enum NumberCardColor { + Red, + Green, + Black, +} + +impl Display for NumberCardColor { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + return write!(f, "{:#?}", self); + } +} + +#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)] +pub struct NumberCard { + pub value: u8, + pub suit: NumberCardColor, +} +impl Display for NumberCard { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + return write!(f, "{} {}", self.suit, self.value); + } +} + +#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] +pub enum CardType { + Hua, + Number(NumberCard), + Special(SpecialCardType), +} + +impl CardType { + #[must_use] + pub fn remove_hua(&self) -> CardTypeNoHua { + match self { + Self::Number(x) => return CardTypeNoHua::Number(x.clone()), + Self::Special(x) => return CardTypeNoHua::Special(x.clone()), + Self::Hua => panic!("Remove hua on hua"), + } + } + + /// Returns a number from (1..=31) + #[must_use] + pub fn to_byte(&self) -> u8 { + match self { + Self::Number(numbercard) => { + let result = numbercard.value + + 9 * (NumberCardColor::into_enum_iter() + .position(|suit| return numbercard.suit == suit) + .unwrap() as u8); + debug_assert!(result >= 1 && result <= 27); + return result; + } + Self::Special(specialcard) => { + let result = 28 + + (SpecialCardType::into_enum_iter() + .position(|x| return x == *specialcard) + .unwrap() as u8); + debug_assert!(result >= 28 && result <= 30); + return result; + } + Self::Hua => return 31, + } + } +} + +impl Display for CardType { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + Self::Hua => return write!(f, "Hua"), + Self::Number(x) => return write!(f, "{}", x), + Self::Special(x) => return write!(f, "{}", x), + } + } +} + +#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone, Ord, PartialOrd, Hash)] +pub enum CardTypeNoHua { + Number(NumberCard), + Special(SpecialCardType), +} +impl Display for CardTypeNoHua { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + Self::Number(x) => return write!(f, "{}", x), + Self::Special(x) => return write!(f, "{}", x), + } + } +} + +impl CardTypeNoHua { + #[must_use] pub fn add_hua(&self) -> CardType { + match self { + Self::Number(x) => return CardType::Number(x.clone()), + Self::Special(x) => return CardType::Special(x.clone()), + } + } +} diff --git a/solver-rs/lib/board/src/fieldposition.rs b/solver-rs/lib/board/src/fieldposition.rs new file mode 100644 index 0000000..42f9f3e --- /dev/null +++ b/solver-rs/lib/board/src/fieldposition.rs @@ -0,0 +1,112 @@ +use serde::de::{self, Deserializer, MapAccess, SeqAccess, Visitor}; +use std::fmt; +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +pub struct FieldPosition { + buffer: u8, +} + +impl FieldPosition { + #[must_use] + pub fn column(&self) -> u8 { + return self.buffer & 0b1111; + } + #[must_use] + pub fn row(&self) -> u8 { + return (self.buffer & (0b1111 << 4)) >> 4; + } + #[must_use] + pub fn new(column: u8, row: u8) -> Self { + debug_assert!(column < 8); + // Should be 13, allowing some buffer for end-markers because we've got the space + debug_assert!(row < 16); + return Self { + buffer: (column & 0b1111) | ((row & 0b1111) << 4), + }; + } +} + +impl std::fmt::Display for FieldPosition { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + return write!(f, "slot #{} index #{}", self.column(), self.row()); + } +} + +impl serde::Serialize for FieldPosition { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut state = serializer.serialize_struct("FieldPosition", 2)?; + state.serialize_field("column", &self.column())?; + state.serialize_field("row", &self.row())?; + return state.end(); + } +} + +impl<'de> serde::Deserialize<'de> for FieldPosition { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + #[derive(serde::Deserialize)] + #[serde(field_identifier, rename_all = "lowercase")] + enum Field { + Column, + Row, + }; + + struct FieldPositionVisitor; + + impl<'de> Visitor<'de> for FieldPositionVisitor { + type Value = FieldPosition; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + return formatter.write_str("struct FieldPosition") + } + + fn visit_seq(self, mut seq: V) -> Result + where + V: SeqAccess<'de>, + { + let column = seq + .next_element()? + .ok_or_else(|| return de::Error::invalid_length(0, &self))?; + let row = seq + .next_element()? + .ok_or_else(|| return de::Error::invalid_length(1, &self))?; + return Ok(FieldPosition::new(column, row)); + } + + fn visit_map(self, mut map: V) -> Result + where + V: MapAccess<'de>, + { + let mut column = None; + let mut row = None; + while let Some(key) = map.next_key()? { + match key { + Field::Column => { + if column.is_some() { + return Err(de::Error::duplicate_field("column")); + } + column = Some(map.next_value()?); + } + Field::Row => { + if row.is_some() { + return Err(de::Error::duplicate_field("row")); + } + row = Some(map.next_value()?); + } + } + } + let column = column.ok_or_else(|| return de::Error::missing_field("column"))?; + let row = row.ok_or_else(|| return de::Error::missing_field("row"))?; + return Ok(FieldPosition::new(column, row)); + } + } + + const FIELDS: &[&str] = &["column", "row"]; + return deserializer.deserialize_struct("Duration", FIELDS, FieldPositionVisitor) + } +} diff --git a/solver-rs/lib/board/src/lib.rs b/solver-rs/lib/board/src/lib.rs new file mode 100644 index 0000000..21dfbee --- /dev/null +++ b/solver-rs/lib/board/src/lib.rs @@ -0,0 +1,54 @@ +#![warn( + clippy::all, + clippy::restriction, + clippy::pedantic, + clippy::nursery, + clippy::cargo +)] +#![allow(clippy::cargo)] +// Style choices +#![allow( + clippy::missing_docs_in_private_items, + clippy::needless_return, + clippy::get_unwrap, + clippy::indexing_slicing, + clippy::explicit_iter_loop +)] +// Way too pedantic +#![allow(clippy::integer_arithmetic)] +#![allow(clippy::integer_division)] +// Useless +#![allow(clippy::missing_inline_in_public_items, clippy::missing_const_for_fn)] +// Useful for production +#![allow( + clippy::use_debug, + clippy::print_stdout, + clippy::dbg_macro, + clippy::panic +)] +// Useful for improving code robustness +#![allow( + clippy::cast_possible_truncation, + clippy::cast_possible_wrap, + clippy::option_unwrap_used, + clippy::option_expect_used, + clippy::as_conversions, + clippy::result_unwrap_used, + clippy::result_expect_used, + // clippy::wildcard_enum_match_arm +)] +#![allow(clippy::trivially_copy_pass_by_ref)] +#![allow(dead_code)] + +mod cards; +pub use cards::*; +mod fieldposition; +pub use fieldposition::*; +mod positions; +pub use positions::*; +mod board_class; +pub use crate::board_class::*; +pub mod test_boards; + +#[cfg(test)] +mod tests; diff --git a/solver-rs/lib/board/src/positions.rs b/solver-rs/lib/board/src/positions.rs new file mode 100644 index 0000000..52eabc6 --- /dev/null +++ b/solver-rs/lib/board/src/positions.rs @@ -0,0 +1,85 @@ +use crate::cards::{CardTypeNoHua, SpecialCardType}; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Ord, PartialOrd, Hash, Clone)] +pub enum BunkerSlot { + Empty, + Blocked(Option), + Stash(CardTypeNoHua), +} + +#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)] +pub enum Position { + Field(crate::FieldPosition), + Bunker { slot_index: u8 }, + Goal { slot_index: u8 }, +} + +impl std::fmt::Display for Position { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + Self::Field(x) => return write!(f, "Field ({})", x), + Self::Bunker { slot_index } => return write!(f, "Bunker #{}", slot_index), + Self::Goal { slot_index } => return write!(f, "Goal #{}", slot_index), + } + } +} + +impl From for Position { + fn from(input: PositionNoGoal) -> Self { + match input { + PositionNoGoal::Field(x) => return Self::Field(x), + PositionNoGoal::Bunker { slot_index } => return Self::Bunker { slot_index }, + }; + } +} + +impl PartialEq for Position { + fn eq(&self, other: &PositionNoGoal) -> bool { + return other.eq(self); + } +} + +#[derive(Debug, Serialize, Deserialize, Clone, Copy, Eq, PartialEq, Hash)] +pub enum PositionNoGoal { + Field(crate::FieldPosition), + Bunker { slot_index: u8 }, +} + +impl std::fmt::Display for PositionNoGoal { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + return write!(f, "{}", Position::from(*self)); + } +} + +#[derive(Debug, Clone)] +pub struct GoalTransformError; + +impl std::convert::TryFrom for PositionNoGoal { + type Error = GoalTransformError; + fn try_from(input: Position) -> Result { + match input { + Position::Field(field_position) => return Result::Ok(Self::Field(field_position)), + Position::Bunker { slot_index } => { + return Result::Ok(Self::Bunker { slot_index }); + } + Position::Goal { .. } => { + return Result::Err(GoalTransformError); + } + } + } +} + +impl PartialEq for PositionNoGoal { + fn eq(&self, other: &Position) -> bool { + let other = >::try_from(other.clone()); + match other { + Ok(other) => { + return Self::eq(self, &other); + } + Err(GoalTransformError) => { + return false; + } + } + } +} diff --git a/solver-rs/lib/board/src/test_boards.rs b/solver-rs/lib/board/src/test_boards.rs new file mode 100644 index 0000000..8623f31 --- /dev/null +++ b/solver-rs/lib/board/src/test_boards.rs @@ -0,0 +1,21 @@ +// This is incredibly shit, as other crates call this macro with _their_ CARGO_MANIFEST_DIR. Ideally we would move +// the boards into the board crate, and use the path of the board crate. But it seems to be really hard to get this done with +// macros, and const variables can't be used by macros, so we're using this hack for now. +#[macro_export] +macro_rules! TEST_BOARD_ROOT { + () => { + concat!(env!("CARGO_MANIFEST_DIR"), + "/../../aux/boards/") + } +} + +#[macro_export] +macro_rules! load_test_board { + ( $relpath:expr ) => { + { + <$crate::Board as std::str::FromStr>::from_str( + include_str!(concat!($crate::TEST_BOARD_ROOT!(), + $relpath))) + } + }; +} \ No newline at end of file diff --git a/solver-rs/lib/board/src/tests.rs b/solver-rs/lib/board/src/tests.rs new file mode 100644 index 0000000..8da918d --- /dev/null +++ b/solver-rs/lib/board/src/tests.rs @@ -0,0 +1,30 @@ +use crate::{CardType, Error, NumberCard, NumberCardColor}; +#[test] +pub fn check_test() -> Result<(), Box> { + // let mut x = Board::from_file(std::path::Path::new(crate::test_boards::SPECIFIC)?; + let mut x = crate::load_test_board!("specific/solved.json")?; + assert_eq!(x.check(), Result::Ok(())); + assert_eq!(x.solved(), true); + x.field[2].push(CardType::Hua); + assert_eq!(x.check(), Result::Err(Error::CardDouble(CardType::Hua))); + x.hua_set = false; + assert_eq!(x.check(), Result::Ok(())); + x.field[2].push(CardType::Number(NumberCard { + suit: NumberCardColor::Black, + value: 9, + })); + assert_eq!( + x.check(), + Result::Err(Error::GoalTooHigh(NumberCard { + value: 9, + suit: NumberCardColor::Black + })) + ); + x.goal[0] = Some(NumberCard { + suit: NumberCardColor::Black, + value: 8, + }); + assert_eq!(x.check(), Result::Ok(())); + assert_eq!(x.solved(), false); + return Result::Ok(()); +} diff --git a/solver-rs/lib/solving/Cargo.toml b/solver-rs/lib/solving/Cargo.toml new file mode 100644 index 0000000..6797c68 --- /dev/null +++ b/solver-rs/lib/solving/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "solving" +version = "0.1.0" +authors = ["Lukas Wölfer "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +board = {path = "../board" } +actions = {path = "../actions"} +graphing = {package = "action_optimization", path = "../action_optimization"} diff --git a/solver-rs/lib/solving/graph.svg b/solver-rs/lib/solving/graph.svg new file mode 100644 index 0000000..fbd8794 --- /dev/null +++ b/solver-rs/lib/solving/graph.svg @@ -0,0 +1,2250 @@ + + + + + + + + + +0 + +Move Green 4 from slot #0 index #4 to slot #7 index #5 + + + +1 + +Move Bai from slot #0 index #3 to bunker #0 + + + +0->1 + + + + + +5 + +Move 2 cards from slot #7 index #4 to slot #1 index #2 + + + +0->5 + + + + + +2 + +Move Zhong from slot #0 index #2 to bunker #1 + + + +1->2 + + + + + +15 + +Move Bai from bunker #0 to slot #0 index #0 + + + +1->15 + + + + + +3 + +Move Black 7 from slot #1 index #3 to slot #0 index #2 + + + +2->3 + + + + + +20 + +Move Zhong from bunker #1 to slot #0 index #0 + + + +2->20 + + + + + +4 + +Move Red 7 from slot #1 index #2 to bunker #2 + + + +3->4 + + + + + +9 + +Move 2 cards from slot #0 index #1 to slot #1 index #1 + + + +3->9 + + + + + +4->5 + + + + + +7 + +Move Red 7 from bunker #2 to slot #3 index #4 + + + +4->7 + + + + + +6 + +Move Green 2 from slot #3 index #4 to slot #7 index #4 + + + +5->6 + + + + + +8 + +Move 3 cards from slot #1 index #1 to slot #3 index #5 + + + +5->8 + + + + + +5->8 + + + + + +6->7 + + + + + +12 + +Move 2 cards from slot #7 index #3 to slot #3 index #7 + + + +6->12 + + + + + +7->8 + + + + + +10 + +Move 5 cards from slot #3 index #3 to slot #5 index #5 + + + +7->10 + + + + + +14 + +Move Fa from slot #0 index #0 to bunker #2 + + + +7->14 + + + + + +8->9 + + + + + +8->10 + + + + + +8->10 + + + + + +8->10 + + + + + +9->14 + + + + + +32 + +Move Green 6 from slot #4 index #1 to slot #1 index #3 + + + +9->32 + + + + + +65 + +Move 6 cards from slot #1 index #1 to slot #0 index #1 + + + +9->65 + + + + + +9->65 + + + + + +11 + +Move 4 cards from slot #5 index #6 to slot #3 index #3 + + + +10->11 + + + + + +10->11 + + + + + +10->11 + + + + + +10->11 + + + + + +10->11 + + + + + +17 + +Move 7 cards from slot #5 index #5 to slot #3 index #2 + + + +10->17 + + + + + +11->12 + + + + + +13 + +Move 6 cards from slot #3 index #3 to slot #5 index #6 + + + +11->13 + + + + + +11->13 + + + + + +11->13 + + + + + +11->13 + + + + + +11->13 + + + + + +12->13 + + + + + +12->13 + + + + + +33 + +Kill Bai to bunker #0 from Bunker #0, Field (slot #2 index #3), Field (slot #4 index #0), Field (slot #7 index #2) + + + +12->33 + + + + + +16 + +Move Green 8 from slot #3 index #2 to bunker #0 + + + +13->16 + + + + + +13->17 + + + + + +13->17 + + + + + +13->17 + + + + + +13->17 + + + + + +13->17 + + + + + +13->17 + + + + + +14->15 + + + + + +26 + +Move Fa from bunker #2 to slot #0 index #0 + + + +14->26 + + + + + +15->16 + + + + + +19 + +Move Bai from slot #0 index #0 to bunker #0 + + + +15->19 + + + + + +16->17 + + + + + +18 + +Move Green 8 from bunker #0 to slot #5 index #5 + + + +16->18 + + + + + +17->18 + + + + + +21 + +Move Green 2 from slot #3 index #8 to bunker #1 + + + +17->21 + + + + + +22 + +Move 5 cards from slot #3 index #3 to slot #5 index #6 + + + +17->22 + + + + + +17->22 + + + + + +17->22 + + + + + +17->22 + + + + + +17->22 + + + + + +39 + +Move 2 cards from slot #3 index #1 to slot #0 index #0 + + + +17->39 + + + + + +18->19 + + + + + +18->22 + + + + + +18->33 + + + + + +66 + +Move 5 cards from slot #5 index #5 to slot #1 index #1 + + + +18->66 + + + + + +19->20 + + + + + +19->33 + + + + + +20->21 + + + + + +25 + +Move Zhong from slot #0 index #0 to bunker #1 + + + +20->25 + + + + + +21->22 + + + + + +24 + +Move Green 2 from bunker #1 to slot #6 index #6 + + + +21->24 + + + + + +23 + +Move Black 3 from slot #5 index #10 to slot #6 index #5 + + + +22->23 + + + + + +22->39 + + + + + +42 + +Move 5 cards from slot #5 index #6 to slot #0 index #2 + + + +22->42 + + + + + +22->42 + + + + + +22->42 + + + + + +22->42 + + + + + +23->24 + + + + + +31 + +Goal Black 3 from Field (slot #6 index #5) to slot #0 + + + +23->31 + + + + + +40 + +Move Red 3 from slot #3 index #0 to slot #5 index #10 + + + +23->40 + + + + + +24->25 + + + + + +30 + +Goal Green 2 from Field (slot #6 index #6) to slot #1 + + + +24->30 + + + + + +25->26 + + + + + +35 + +Move Zhong from bunker #1 to slot #4 index #0 + + + +25->35 + + + + + +27 + +Move Fa from slot #4 index #4 to bunker #2 + + + +26->27 + + + + + +38 + +Move Fa from slot #0 index #0 to bunker #1 + + + +26->38 + + + + + +28 + +Goal Black 2 from Field (slot #4 index #3) to slot #0 + + + +27->28 + + + + + +59 + +Move Fa from bunker #2 to slot #6 index #0 + + + +27->59 + + + + + +29 + +Goal Green 1 from Field (slot #4 index #2) to slot #1 + + + +28->29 + + + + + +28->31 + + + + + +29->30 + + + + + +29->32 + + + + + +30->31 + + + + + +75 + +Goal Green 3 from Field (slot #2 index #0) to slot #1 + + + +30->75 + + + + + +36 + +Move 2 cards from slot #6 index #3 to slot #1 index #4 + + + +31->36 + + + + + +47 + +Goal Black 4 from Field (slot #6 index #1) to slot #0 + + + +31->47 + + + + + +32->33 + + + + + +32->36 + + + + + +52 + +Move 4 cards from slot #1 index #3 to slot #5 index #7 + + + +32->52 + + + + + +34 + +Goal Red 1 from Field (slot #7 index #1) to slot #2 + + + +33->34 + + + + + +33->35 + + + + + +72 + +Move Fa from slot #2 index #2 to bunker #1 + + + +33->72 + + + + + +79 + +Kill Zhong to bunker #1 from Bunker #1, Bunker #2, Field (slot #5 index #3), Field (slot #7 index #0) + + + +34->79 + + + + + +80 + +Goal Red 2 from Field (slot #5 index #2) to slot #2 + + + +34->80 + + + + + +35->38 + + + + + +77 + +Move Zhong from slot #4 index #0 to bunker #1 + + + +35->77 + + + + + +37 + +Move Red 4 from slot #1 index #5 to slot #6 index #3 + + + +36->37 + + + + + +36->37 + + + + + +43 + +Move Black 5 from slot #1 index #4 to bunker #1 + + + +36->43 + + + + + +37->43 + + + + + +46 + +Move 2 cards from slot #6 index #2 to slot #5 index #8 + + + +37->46 + + + + + +38->39 + + + + + +41 + +Move Fa from bunker #1 to slot #3 index #0 + + + +38->41 + + + + + +39->40 + + + + + +39->42 + + + + + +64 + +Move Black 8 from slot #0 index #1 to bunker #1 + + + +39->64 + + + + + +96 + +Goal Green 9 from Field (slot #0 index #0) to slot #1 + + + +39->96 + + + + + +40->41 + + + + + +40->42 + + + + + +41->43 + + + + + +88 + +Kill Fa to bunker #2 from Field (slot #2 index #0), Field (slot #3 index #0), Field (slot #5 index #1), Field (slot #6 index #0) + + + +41->88 + + + + + +44 + +Move 3 cards from slot #0 index #4 to slot #1 index #4 + + + +42->44 + + + + + +42->44 + + + + + +42->44 + + + + + +45 + +Move 2 cards from slot #0 index #2 to slot #5 index #6 + + + +42->45 + + + + + +42->45 + + + + + +42->45 + + + + + +43->44 + + + + + +48 + +Goal Black 5 from Bunker #1 to slot #0 + + + +43->48 + + + + + +44->45 + + + + + +44->52 + + + + + +44->52 + + + + + +44->52 + + + + + +45->46 + + + + + +49 + +Move 4 cards from slot #5 index #6 to slot #0 index #2 + + + +45->49 + + + + + +45->49 + + + + + +45->49 + + + + + +46->47 + + + + + +46->49 + + + + + +46->49 + + + + + +47->48 + + + + + +50 + +Move 3 cards from slot #0 index #3 to slot #6 index #1 + + + +47->50 + + + + + +54 + +Move Red 3 from slot #0 index #6 to bunker #1 + + + +48->54 + + + + + +87 + +Goal Black 6 from Field (slot #1 index #3) to slot #0 + + + +48->87 + + + + + +49->50 + + + + + +49->50 + + + + + +49->50 + + + + + +51 + +Move Red 7 from slot #0 index #2 to slot #5 index #6 + + + +49->51 + + + + + +49->51 + + + + + +50->51 + + + + + +57 + +Move 4 cards from slot #6 index #0 to slot #0 index #2 + + + +50->57 + + + + + +50->57 + + + + + +50->57 + + + + + +51->52 + + + + + +53 + +Move 5 cards from slot #5 index #6 to slot #0 index #2 + + + +51->53 + + + + + +51->53 + + + + + +52->53 + + + + + +52->53 + + + + + +52->53 + + + + + +52->53 + + + + + +56 + +Move 3 cards from slot #5 index #7 to slot #1 index #3 + + + +52->56 + + + + + +53->54 + + + + + +55 + +Move 4 cards from slot #0 index #2 to slot #5 index #6 + + + +53->55 + + + + + +53->55 + + + + + +53->55 + + + + + +53->55 + + + + + +53->55 + + + + + +54->55 + + + + + +58 + +Move Red 3 from bunker #1 to slot #1 index #6 + + + +54->58 + + + + + +55->56 + + + + + +55->56 + + + + + +55->56 + + + + + +55->57 + + + + + +55->66 + + + + + +56->58 + + + + + +61 + +Move 2 cards from slot #0 index #3 to slot #5 index #7 + + + +56->61 + + + + + +56->65 + + + + + +56->65 + + + + + +56->65 + + + + + +57->59 + + + + + +60 + +Move Red 4 from slot #0 index #5 to bunker #1 + + + +57->60 + + + + + +57->61 + + + + + +57->61 + + + + + +62 + +Move Green 7 from slot #0 index #2 to bunker #2 + + + +57->62 + + + + + +58->60 + + + + + +58->65 + + + + + +59->62 + + + + + +59->88 + + + + + +60->61 + + + + + +63 + +Move Red 4 from bunker #1 to slot #5 index #9 + + + +60->63 + + + + + +61->62 + + + + + +61->63 + + + + + +61->66 + + + + + +61->66 + + + + + +62->64 + + + + + +68 + +Move Green 7 from bunker #2 to slot #5 index #6 + + + +62->68 + + + + + +63->64 + + + + + +63->66 + + + + + +64->65 + + + + + +67 + +Move Black 8 from bunker #1 to slot #5 index #5 + + + +64->67 + + + + + +65->66 + + + + + +69 + +Move Red 3 from slot #0 index #6 to bunker #1 + + + +65->69 + + + + + +82 + +Goal Green 4 from Field (slot #0 index #5) to slot #1 + + + +65->82 + + + + + +84 + +Goal Red 5 from Field (slot #0 index #4) to slot #2 + + + +65->84 + + + + + +86 + +Goal Green 6 from Field (slot #0 index #3) to slot #1 + + + +65->86 + + + + + +90 + +Goal Black 7 from Field (slot #0 index #2) to slot #0 + + + +65->90 + + + + + +93 + +Goal Red 8 from Field (slot #0 index #1) to slot #2 + + + +65->93 + + + + + +66->67 + + + + + +70 + +Move Red 4 from slot #1 index #5 to bunker #2 + + + +66->70 + + + + + +85 + +Goal Green 5 from Field (slot #1 index #4) to slot #1 + + + +66->85 + + + + + +66->87 + + + + + +91 + +Goal Red 7 from Field (slot #1 index #2) to slot #2 + + + +66->91 + + + + + +94 + +Goal Green 8 from Field (slot #1 index #1) to slot #1 + + + +66->94 + + + + + +67->68 + + + + + +67->69 + + + + + +78 + +Move 3 cards from slot #5 index #4 to slot #4 index #0 + + + +67->78 + + + + + +68->70 + + + + + +68->78 + + + + + +71 + +Move Red 3 from bunker #1 to slot #0 index #6 + + + +69->71 + + + + + +69->71 + + + + + +73 + +Move Red 4 from bunker #2 to slot #1 index #5 + + + +70->73 + + + + + +70->73 + + + + + +71->72 + + + + + +81 + +Goal Red 3 from Field (slot #0 index #6) to slot #2 + + + +71->81 + + + + + +74 + +Move Zhong from slot #2 index #1 to bunker #2 + + + +72->74 + + + + + +76 + +Move Fa from bunker #1 to slot #2 index #0 + + + +72->76 + + + + + +73->74 + + + + + +83 + +Goal Red 4 from Field (slot #1 index #5) to slot #2 + + + +73->83 + + + + + +74->75 + + + + + +74->79 + + + + + +75->76 + + + + + +75->82 + + + + + +76->77 + + + + + +76->79 + + + + + +76->88 + + + + + +77->78 + + + + + +77->79 + + + + + +78->79 + + + + + +92 + +Goal Green 7 from Field (slot #4 index #2) to slot #1 + + + +78->92 + + + + + +95 + +Goal Black 8 from Field (slot #4 index #1) to slot #0 + + + +78->95 + + + + + +98 + +Goal Red 9 from Field (slot #4 index #0) to slot #2 + + + +78->98 + + + + + +79->80 + + + + + +79->88 + + + + + +80->81 + + + + + +80->88 + + + + + +81->82 + + + + + +81->83 + + + + + +82->84 + + + + + +82->85 + + + + + +83->84 + + + + + +83->85 + + + + + +84->86 + + + + + +89 + +Goal Red 6 from Field (slot #5 index #0) to slot #2 + + + +84->89 + + + + + +85->86 + + + + + +85->87 + + + + + +86->90 + + + + + +86->92 + + + + + +87->90 + + + + + +87->91 + + + + + +88->89 + + + + + +89->91 + + + + + +90->93 + + + + + +90->95 + + + + + +91->93 + + + + + +91->94 + + + + + +92->94 + + + + + +92->95 + + + + + +93->96 + + + + + +93->98 + + + + + +94->96 + + + + + +97 + +Goal Black 9 from Field (slot #1 index #0) to slot #0 + + + +94->97 + + + + + +95->97 + + + + + +95->98 + + + + + diff --git a/solver-rs/lib/solving/src/benchmark.rs b/solver-rs/lib/solving/src/benchmark.rs new file mode 100644 index 0000000..63b9163 --- /dev/null +++ b/solver-rs/lib/solving/src/benchmark.rs @@ -0,0 +1,63 @@ +use super::solve; + +#[must_use] +pub fn actions_correct(actions: &[actions::All], mut board: board::Board, verbose: bool) -> bool { + for (index, action) in actions.iter().enumerate() { + if verbose { + println!("Action #{:3}: {}", index, action); + } + action.apply(&mut board); + } + return board.solved(); +} +fn run_test(board: board::Board) -> (f32, usize) { + use std::io::Write; + std::io::stdout().flush().expect("Flushing did not work"); + assert_eq!(board.check(), Result::Ok(())); + let start_time = std::time::Instant::now(); + let result = solve(&board); + let result_time = start_time.elapsed().as_secs_f32(); + assert!(!result.is_err()); + let mut result_length: usize = 0; + if let Result::Ok(actions) = result { + assert!(actions_correct(&actions, board, false)); + result_length = actions.len(); + } + return (result_time, result_length); +} +fn run_all_tests( + dirname: &std::path::Path, + exclude: &[&str], +) -> Result<(), Box> { + for board_json in std::fs::read_dir(dirname)? { + let board_json = board_json?; + if exclude.contains( + &board_json + .path() + .as_path() + .file_name() + .unwrap() + .to_str() + .unwrap(), + ) { + continue; + } + let x = board::Board::from_file(&board_json.path())?; + print!( + "> {:<20} ", + board_json.path().file_stem().unwrap().to_string_lossy(), + ); + let (time, length) = run_test(x); + println!("{:.02} {:3}", time, length); + } + return Result::Ok(()); +} + +#[test] +#[ignore] +pub fn possible() -> Result<(), Box> { + //! # Errors + let whole_board_dir: std::path::PathBuf = [board::TEST_BOARD_ROOT!(), "normal"].iter().collect(); + println!("{:?}", whole_board_dir); + return run_all_tests(&whole_board_dir, &[]); +} \ No newline at end of file diff --git a/solver-rs/lib/solving/src/board_state_iterator/action_board.rs b/solver-rs/lib/solving/src/board_state_iterator/action_board.rs new file mode 100644 index 0000000..f3aabe1 --- /dev/null +++ b/solver-rs/lib/solving/src/board_state_iterator/action_board.rs @@ -0,0 +1,30 @@ +#[derive(Clone, Debug)] +pub(super) struct ActionBoard { + board: board::Board, + stack: Vec, +} + +impl ActionBoard { + pub(super) fn new(board: board::Board) -> Self { + return Self { + board, + stack: Vec::new(), + }; + } + pub(super) fn push(&mut self, action: actions::All) { + action.apply(&mut self.board); + self.stack.push(action); + debug_assert_eq!(self.board.check(), Result::Ok(())); + } + pub(super) fn pop(&mut self) -> Option { + if let Option::Some(action) = self.stack.pop() { + action.undo(&mut self.board); + debug_assert_eq!(self.board.check(), Result::Ok(())); + return Option::Some(action); + } + return Option::None; + } + pub(super) const fn board(&self) -> &board::Board { + return &self.board; + } +} diff --git a/solver-rs/lib/solving/src/board_state_iterator/adapter/base.rs b/solver-rs/lib/solving/src/board_state_iterator/adapter/base.rs new file mode 100644 index 0000000..6f628ac --- /dev/null +++ b/solver-rs/lib/solving/src/board_state_iterator/adapter/base.rs @@ -0,0 +1,32 @@ +use super::{ super::BoardState}; +use crate::board_state_iterator::BoardStateIterator; +use super::loop_move_avoider::LoopMoveAvoider; +pub(crate) trait BoardStateIteratorAdapter { + fn advance(&mut self); + fn get(&mut self) -> Option; + fn next(&mut self) -> Option { + self.advance(); + return self.get(); + } + fn unique(self) -> super::Unique + where + Self: Sized, + { + return super::Unique::new(self); + } + + fn avoid_loops(self) -> LoopMoveAvoider + where Self: Sized, + { + return LoopMoveAvoider::new(self); + } +} + +impl BoardStateIteratorAdapter for BoardStateIterator { + fn advance(&mut self) { + self.advance(); + } + fn get(&mut self) -> Option { + return self.get(); + } +} diff --git a/solver-rs/lib/solving/src/board_state_iterator/adapter/loop_move_avoider.rs b/solver-rs/lib/solving/src/board_state_iterator/adapter/loop_move_avoider.rs new file mode 100644 index 0000000..64bc4e1 --- /dev/null +++ b/solver-rs/lib/solving/src/board_state_iterator/adapter/loop_move_avoider.rs @@ -0,0 +1,38 @@ +use super::super::BoardState; +use super::BoardStateIteratorAdapter; +pub(crate) struct LoopMoveAvoider { + base_iterator: T, +} +impl LoopMoveAvoider { + pub(crate) fn new(base_iterator: T) -> Self { + return Self { base_iterator }; + } + fn is_loop_move(state: &BoardState) -> bool { + let last_action = state.action_stack().rev().next(); + if let Option::Some(actions::All::Move(last_move_action)) = last_action { + let loop_move = state.action_stack().rev().skip(1).find(|x| { + if let actions::All::Move(action) = x { + return action.cards() == last_move_action.cards(); + } else { + return false; + } + }); + return loop_move.is_some(); + } else { + return false; + } + } +} +impl BoardStateIteratorAdapter for LoopMoveAvoider { + fn advance(&mut self) { + while let Option::Some(mut state) = self.base_iterator.next() { + if !Self::is_loop_move(&state) { + return; + } + state.kill(); + } + } + fn get(&mut self) -> Option { + return self.base_iterator.get(); + } +} diff --git a/solver-rs/lib/solving/src/board_state_iterator/adapter/mod.rs b/solver-rs/lib/solving/src/board_state_iterator/adapter/mod.rs new file mode 100644 index 0000000..889ffdc --- /dev/null +++ b/solver-rs/lib/solving/src/board_state_iterator/adapter/mod.rs @@ -0,0 +1,5 @@ +mod loop_move_avoider; +mod unique; +pub(crate) use unique::*; +mod base; +pub(crate) use base::*; diff --git a/solver-rs/lib/solving/src/board_state_iterator/adapter/unique.rs b/solver-rs/lib/solving/src/board_state_iterator/adapter/unique.rs new file mode 100644 index 0000000..6668103 --- /dev/null +++ b/solver-rs/lib/solving/src/board_state_iterator/adapter/unique.rs @@ -0,0 +1,30 @@ +use super::super::BoardState; +use super::BoardStateIteratorAdapter; + +pub(crate) struct Unique { + base_iterator: T, + known_boards: std::collections::HashSet, +} +impl Unique { + pub(crate) fn new(base_iterator: T) -> Self { + return Self { + base_iterator, + known_boards: std::collections::HashSet::new(), + }; + } +} +impl BoardStateIteratorAdapter for Unique { + fn get(&mut self) -> Option { + return self.base_iterator.get(); + } + fn advance(&mut self) { + while let Option::Some(mut nextboard) = self.base_iterator.next() { + let eq_hash = nextboard.board().equivalence_hash(); + if !self.known_boards.contains(&eq_hash) { + self.known_boards.insert(eq_hash); + return; + } + nextboard.kill(); + } + } +} diff --git a/solver-rs/lib/solving/src/board_state_iterator/base.rs b/solver-rs/lib/solving/src/board_state_iterator/base.rs new file mode 100644 index 0000000..44a57db --- /dev/null +++ b/solver-rs/lib/solving/src/board_state_iterator/base.rs @@ -0,0 +1,105 @@ +use super::action_board::ActionBoard; +use super::stack_frame::StackFrame; + +#[derive(Debug)] +pub(crate) struct BoardState<'a> { + state_it: &'a mut BoardStateIterator, +} +impl<'a> BoardState<'a> { + pub(crate) fn new(state_it: &'a mut BoardStateIterator) -> Self { + return Self { state_it }; + } + pub(crate) fn board(&'a self) -> &'a board::Board { + return self.state_it.board.board(); + } + pub(crate) fn action_stack( + &'a self, + ) -> Box + 'a> { + return self.state_it.action_stack(); + } + pub(crate) fn kill(&'a mut self) { + if let Option::Some(node) = self.state_it.stack.last_mut() { + node.taint_child(); + } + } +} + +#[derive(Clone, Debug)] +pub(crate) struct BoardStateIterator { + board: ActionBoard, + stack: Vec, +} + +impl BoardStateIterator { + pub(crate) fn new(board: board::Board) -> Self { + let mut result = Self { + board: ActionBoard::new(board), + stack: Vec::new(), + }; + let actions = actions::possibilities::filter_actions(result.board.board()); + if !actions.is_empty() { + result.push(actions); + } + return result; + } + + fn unwind(&mut self) { + for i in (0..self.stack.len()).rev() { + self.board.pop(); + if let Option::Some(action) = self.stack[i].next() { + self.board.push(action.clone()); + return; + } + self.stack.pop(); + } + } + + fn pop(&mut self) { + if self.stack.is_empty() { + return; + } + assert_ne!(self.stack.pop().unwrap().get(), Option::None); + self.board.pop(); + self.stack.pop(); + self.unwind(); + } + + fn push(&mut self, actions: Vec) { + assert!(!actions.is_empty()); + self.board.push(actions.first().unwrap().clone()); + self.stack.push(StackFrame::new(actions)); + } + + fn action_stack<'a>( + &'a self, + ) -> Box + 'a> { + return Box::new(self.stack.iter().map(|x| return x.get().unwrap().clone())); + } + + pub(crate) fn get(&mut self) -> Option { + if self.stack.is_empty() { + return Option::None; + } + return Option::Some(BoardState::new(self)); + } + + pub(crate) fn next(&mut self) -> Option { + self.advance(); + return self.get(); + } + + pub(crate) fn advance(&mut self) { + if let Option::Some(node) = self.stack.last() { + if node.child_tainted() { + return self.unwind(); + } + } + if let Option::Some(current_board) = self.get() { + let actions = actions::possibilities::filter_actions(current_board.board()); + if actions.is_empty() { + return self.unwind(); + } + self.push(actions); + } + } +} diff --git a/solver-rs/lib/solving/src/board_state_iterator/board_state_tree.rs b/solver-rs/lib/solving/src/board_state_iterator/board_state_tree.rs new file mode 100644 index 0000000..1319503 --- /dev/null +++ b/solver-rs/lib/solving/src/board_state_iterator/board_state_tree.rs @@ -0,0 +1,86 @@ +enum SearcherNodeState<'a> { + Unexplored, + Exhausted, + Exploring(Box>), +} + +struct SearcherNode<'a> { + children: Vec>, + parent: &'a SearcherNodeType<'a>, + parent_id: usize, + action: board::actions::All, +} +struct SearcherNodeRoot<'a> { + children: Vec>, +} + +enum SearcherNodeType<'a> { + Root(SearcherNodeRoot<'a>), + Normal(SearcherNode<'a>), +} + +fn toSearcherNodes<'a>( + parent: &'a SearcherNodeType<'a>, + actions: Vec, +) -> Vec> { + return actions + .into_iter() + .enumerate() + .map(|(index, action)| { + return SearcherNodeState::Exploring(Box::new(SearcherNode { + parent, + children: vec![], + parent_id: index, + action, + })); + }) + .collect(); +} +struct Searcher<'a> { + root: SearcherNodeRoot<'a>, + board: board::Board, + current_node: Option<&'a mut SearcherNodeState<'a>>, + current_board: board::Board, +} +impl<'a> Searcher<'a> { + pub(crate) fn new(board: board::Board) -> Self { + let actions = super::filter_actions(&board, &board::possibilities::all_actions(&board)); + let mut root = SearcherNodeRoot { children: vec![] }; + root.children = toSearcherNodes(&SearcherNodeType::Root(root), actions); + + let mut current_board = board.clone(); + let current_node = root.children.first_mut(); + if let Option::Some(SearcherNodeState::Exploring(action_node)) = current_node { + action_node.action.apply(&mut current_board); + } + + return Self { + root, + board, + current_node, + current_board, + }; + } + pub(crate) fn advance(&'a mut self) { + if let Option::Some(action_node) = self.current_node { + if let SearcherNodeState::Exploring(expl_action_node) = action_node { + let actions = super::filter_actions( + &self.current_board, + &board::possibilities::all_actions(&self.current_board), + ); + expl_action_node.children = + toSearcherNodes(&SearcherNodeType::Normal(**expl_action_node), actions); + } + } + } + pub(crate) fn get(&'a self) -> Option<&'a board::Board> { + self.current_node?; + return Option::Some(&self.current_board); + } + pub(crate) fn next(&'a mut self) -> Option<&'a board::Board> { + self.advance(); + return self.get(); + } + pub(crate) fn kill_children(&'a mut self) { + } +} \ No newline at end of file diff --git a/solver-rs/lib/solving/src/board_state_iterator/mod.rs b/solver-rs/lib/solving/src/board_state_iterator/mod.rs new file mode 100644 index 0000000..1c33bf2 --- /dev/null +++ b/solver-rs/lib/solving/src/board_state_iterator/mod.rs @@ -0,0 +1,5 @@ +mod action_board; +pub mod adapter; +mod base; +mod stack_frame; +pub(crate) use base::*; diff --git a/solver-rs/lib/solving/src/board_state_iterator/stack_frame.rs b/solver-rs/lib/solving/src/board_state_iterator/stack_frame.rs new file mode 100644 index 0000000..587d656 --- /dev/null +++ b/solver-rs/lib/solving/src/board_state_iterator/stack_frame.rs @@ -0,0 +1,36 @@ +#[derive(Clone, Debug)] +pub(super) struct StackFrame { + all_options: Vec, + options_iter: usize, + child_tainted: bool, +} +impl StackFrame { + pub(super) fn new(actions: Vec) -> Self { + return Self { + all_options: actions, + child_tainted: false, + options_iter: 0, + }; + } + pub(super) fn get(&self) -> Option<&actions::All> { + if self.options_iter >= self.all_options.len() { + return Option::None; + } + return Option::Some(&self.all_options[self.options_iter]); + } + pub(super) fn advance(&mut self) { + self.options_iter += 1; + self.child_tainted = false; + } + pub(super) fn next(&mut self) -> Option<&actions::All> { + self.advance(); + return self.get(); + } + pub(super) fn taint_child(&mut self) { + assert_eq!(self.child_tainted, false); + self.child_tainted = true; + } + pub(super) fn child_tainted(&self) -> bool { + return self.child_tainted; + } +} diff --git a/solver-rs/lib/solving/src/lib.rs b/solver-rs/lib/solving/src/lib.rs new file mode 100644 index 0000000..ed0687b --- /dev/null +++ b/solver-rs/lib/solving/src/lib.rs @@ -0,0 +1,46 @@ +#![warn( + clippy::all, + clippy::restriction, + clippy::pedantic, + clippy::nursery, + clippy::cargo +)] +#![allow(clippy::cargo)] +// Style choices +#![allow( + clippy::missing_docs_in_private_items, + clippy::needless_return, + clippy::get_unwrap, + clippy::indexing_slicing, + clippy::explicit_iter_loop, + clippy::redundant_pub_crate, // Just dont understand it, maybe fix instead? +)] +// Way too pedantic +#![allow(clippy::integer_arithmetic)] +// Useless +#![allow(clippy::missing_inline_in_public_items, clippy::missing_const_for_fn)] +// Useful for production +#![allow( + clippy::use_debug, + clippy::print_stdout, + clippy::dbg_macro, + clippy::panic +)] +// Useful for improving code robustness +#![allow( + clippy::cast_possible_truncation, + clippy::cast_possible_wrap, + clippy::option_unwrap_used, + clippy::result_unwrap_used, + clippy::result_expect_used, + // clippy::wildcard_enum_match_arm +)] +#![allow(clippy::trivially_copy_pass_by_ref)] +#![allow(dead_code)] + +mod board_state_iterator; +mod solve; +pub use solve::*; +pub mod benchmark; +#[cfg(test)] +pub mod tests; diff --git a/solver-rs/lib/solving/src/solve.rs b/solver-rs/lib/solving/src/solve.rs new file mode 100644 index 0000000..e233528 --- /dev/null +++ b/solver-rs/lib/solving/src/solve.rs @@ -0,0 +1,30 @@ +use super::board_state_iterator::adapter::BoardStateIteratorAdapter; +use super::board_state_iterator::BoardStateIterator; + +#[derive(Debug)] +pub struct Error {} + +impl std::fmt::Display for Error { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + return write!(f, "Board options exhausted, no solution found"); + } +} + +impl std::error::Error for Error {} + +pub fn solve(solboard: &board::Board) -> Result, Error> { + //! # Errors + //! Returns error when no solution could be found + if solboard.solved() { + return Result::Ok(vec![]); + } + let mut stack = BoardStateIterator::new(solboard.clone()) + .unique() + .avoid_loops(); + while let Option::Some(current_board) = stack.next() { + if current_board.board().solved() { + return Result::Ok(current_board.action_stack().collect()); + } + } + return Result::Err(Error {}); +} diff --git a/solver-rs/lib/solving/src/tests.rs b/solver-rs/lib/solving/src/tests.rs new file mode 100644 index 0000000..0346e24 --- /dev/null +++ b/solver-rs/lib/solving/src/tests.rs @@ -0,0 +1,11 @@ +use crate::solve; + +#[test] +pub fn test_almost_solved() -> Result<(), Box> { + //! # Errors + let x = board::load_test_board!("specific/scarce.json")?; + assert_eq!(x.check(), Result::Ok(())); + let result = solve(&x); + assert!(result.is_ok()); + return Result::Ok(()); +} diff --git a/solver-rs/src/bin/opt.rs b/solver-rs/src/bin/opt.rs new file mode 100644 index 0000000..b85184f --- /dev/null +++ b/solver-rs/src/bin/opt.rs @@ -0,0 +1,83 @@ +#![allow(clippy::needless_return)] + +use std::{io::Read, path::PathBuf}; +use structopt::StructOpt; + +#[derive(Debug, StructOpt)] +#[structopt( + name = "shenzhen opt", + about = "Optimizer for solutions to the shenzhen I/O solitaire minigame" +)] +struct Opt { + /// Input for JSON board, default is stdin + #[structopt(short, long, parse(from_os_str))] + input: Option, + + /// Output for JSON action sequence, default is stdout + #[structopt(short, long, parse(from_os_str))] + output: Option, + + /// Print information about solving + #[structopt(short, long)] + verbose: bool, + + /// Draw dependency graph in 'dot' format instead of actions instead of optimizing + #[structopt(short, long)] + graph: bool, + + /// Prettify JSON output + #[structopt(short, long)] + pretty: bool, +} + +fn optimize( + actions: &[actions::All], + verbose: bool, +) -> Result> { + if verbose { + eprintln!("Starting optimization at {} actions", actions.len()); + } + let start_time = std::time::Instant::now(); + let optimized_actions = action_optimization::optimize(&actions); + + if verbose { + eprintln!( + "Optimized to {} actions in {:.2} seconds", + optimized_actions.len(), + start_time.elapsed().as_secs_f32() + ); + } + let serialized_actions = serde_json::to_string(&optimized_actions)?; + + return Result::Ok(serialized_actions); +} + +fn graph(actions: &[actions::All]) -> Result> { + let graph_actions = action_optimization::dot_actions(actions); + return Result::Ok(graph_actions); +} + +fn main() -> Result<(), Box> { + let opts = Opt::from_args(); + let buffer = if let Option::Some(input) = opts.input { + std::fs::read_to_string(input)? + } else { + let mut buffer = String::new(); + std::io::stdin().read_to_string(&mut buffer)?; + buffer + }; + let action_sequence: Vec = serde_json::from_str(&buffer)?; + + let output = if opts.graph { + graph(&action_sequence)? + } else { + optimize(&action_sequence, opts.verbose)? + }; + if let Option::Some(output_file) = opts.output { + std::fs::write(output_file, output)?; + } else { + println!("{}", output); + } + + return Result::Ok(()); +} diff --git a/solver-rs/src/bin/solver.rs b/solver-rs/src/bin/solver.rs new file mode 100644 index 0000000..146764a --- /dev/null +++ b/solver-rs/src/bin/solver.rs @@ -0,0 +1,88 @@ +use std::io::Read; +use std::{path::PathBuf, str::FromStr}; +use structopt::StructOpt; + +#[derive(Debug, StructOpt)] +#[structopt( + name = "shenzhen solver", + about = "Solver for the shenzhen I/O solitaire minigame" +)] +struct Opt { + /// Input for JSON board, default is stdin + #[structopt(short, long, parse(from_os_str))] + input: Option, + + /// Output for JSON action sequence, default is stdout + #[structopt(short, long, parse(from_os_str))] + output: Option, + + /// Print information about solving + #[structopt(short, long)] + verbose: bool, + + /// Optimize result action sequence + #[structopt(short = "-r", long)] + optimize: bool, + + /// Prettify JSON output + #[structopt(short, long)] + pretty: bool, +} + +#[allow(clippy::needless_return)] +pub fn main() -> Result<(), Box> { + let opts = Opt::from_args(); + let buffer = if let Option::Some(input) = opts.input { + std::fs::read_to_string(input)? + } else { + let mut buffer = String::new(); + std::io::stdin().read_to_string(&mut buffer)?; + buffer + }; + + let board = board::Board::from_str(&buffer)?; + + let start_time = std::time::Instant::now(); + if opts.verbose { + eprintln!("Start solving"); + } + let action_sequence = solving::solve(&board)?; + if opts.verbose { + eprintln!( + "Finished solving in {:.2}s", + std::time::Instant::now() + .duration_since(start_time) + .as_secs_f32() + ); + } + + if opts.verbose { + eprintln!("Action count in sequence: {:3}", action_sequence.len()); + } + let action_sequence = if opts.optimize { + let optimized_actions = action_optimization::optimize(&action_sequence); + if opts.verbose { + eprintln!("Optimized action count: {:3}", optimized_actions.len()); + } + optimized_actions + } else { + action_sequence + }; + assert!(solving::benchmark::actions_correct( + &action_sequence, + board, + false + )); + + let serialized_actions = if opts.pretty { + serde_json::to_string_pretty(&action_sequence)? + } else { + serde_json::to_string(&action_sequence)? + }; + if let Option::Some(output) = opts.output { + std::fs::write(output, serialized_actions)?; + } else { + println!("{}", serialized_actions); + } + return Result::Ok(()); +} diff --git a/solver-rs/src/lib.rs b/solver-rs/src/lib.rs new file mode 100644 index 0000000..925a521 --- /dev/null +++ b/solver-rs/src/lib.rs @@ -0,0 +1,58 @@ +#![warn( + clippy::all, + clippy::restriction, + clippy::pedantic, + clippy::nursery, + clippy::cargo +)] +#![allow(clippy::cargo)] +// Style choices +#![allow( + clippy::missing_docs_in_private_items, + clippy::needless_return, + clippy::get_unwrap, + clippy::indexing_slicing, + clippy::explicit_iter_loop +)] +// Way too pedantic +#![allow(clippy::integer_arithmetic)] +// Useless +#![allow(clippy::missing_inline_in_public_items, clippy::missing_const_for_fn)] +// Useful for production +#![allow( + clippy::use_debug, + clippy::print_stdout, + clippy::dbg_macro, + clippy::panic +)] +// Useful for improving code robustness +#![allow( + clippy::cast_possible_truncation, + clippy::cast_possible_wrap, + clippy::option_unwrap_used, + // clippy::result_unwrap_used, + // clippy::wildcard_enum_match_arm +)] +#![allow(clippy::trivially_copy_pass_by_ref)] +#![allow(dead_code)] + +#[test] +#[ignore] +fn struct_size_printer() { + macro_rules! print_size{ + ($x:ty) => { + println!("{:30} {:3} {:3}", std::stringify!($x), std::mem::size_of::<$x>(), std::mem::align_of::<$x>()); + } + } + print_size!(board::Board); + print_size!(board::BoardEqHash); + print_size!(actions::All); + print_size!(actions::DragonKill); + print_size!(actions::Move); + print_size!(actions::Bunkerize); + print_size!(actions::Goal); + print_size!(actions::HuaKill); + print_size!(board::FieldPosition); + print_size!(board::PositionNoGoal); + print_size!(board::CardType); +}