diff --git a/rust_project/Cargo.lock b/rust_project/Cargo.lock index 0eb090d7..991aff88 100644 --- a/rust_project/Cargo.lock +++ b/rust_project/Cargo.lock @@ -2124,7 +2124,7 @@ dependencies = [ [[package]] name = "loda-rust-cli" -version = "2023.11.29" +version = "2023.12.12" dependencies = [ "ahash", "alphanumeric-sort", diff --git a/rust_project/loda-rust-cli/Cargo.toml b/rust_project/loda-rust-cli/Cargo.toml index 90f018c8..95be1d78 100644 --- a/rust_project/loda-rust-cli/Cargo.toml +++ b/rust_project/loda-rust-cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "loda-rust-cli" -version = "2023.11.29" +version = "2023.12.12" authors = ["Simon Strandgaard "] description = "Command line interface for LODA Rust" repository = "https://github.com/loda-lang/loda-rust" diff --git a/rust_project/loda-rust-cli/src/arc/cellular_automaton.rs b/rust_project/loda-rust-cli/src/arc/cellular_automaton.rs index 303b340e..65e53f00 100644 --- a/rust_project/loda-rust-cli/src/arc/cellular_automaton.rs +++ b/rust_project/loda-rust-cli/src/arc/cellular_automaton.rs @@ -251,8 +251,41 @@ pub mod rule { } } -} // mod rule + /// Create a cave system + /// https://www.roguebasin.com/index.php/Cellular_Automata_Method_for_Generating_Random_Cave-Like_Levels + /// http://pixelenvy.ca/wa/ca_cave.html + pub struct Cave; + + impl super::CARule for Cave { + fn apply(center: u8, neighbors: &[u8; 8]) -> u8 { + let alive_count: usize = neighbors.iter().filter(|&&value| value > 0).count(); + if alive_count < 4 { + return 0; + } + if alive_count > 5 { + return 1; + } + center + } + } + /// Create a maze + /// https://conwaylife.com/wiki/OCA:Maze + pub struct Maze; + + impl super::CARule for Maze { + fn apply(center: u8, neighbors: &[u8; 8]) -> u8 { + let alive_count: usize = neighbors.iter().filter(|&&value| value > 0).count(); + if alive_count == 3 { + return 1; + } + if alive_count < 1 || alive_count > 5 { + return 0; + } + center + } + } +} // mod rule #[cfg(test)] mod tests { @@ -529,4 +562,82 @@ mod tests { let expected: Image = Image::try_create(6, 6, expected_pixels).expect("image"); assert_eq!(actual, expected); } + + #[test] + fn test_60000_cave() { + // Act + let pixels: Vec = vec![ + 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, + 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, + 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, + 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, + 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, + 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, + 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, + 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, + 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, + 1, 1, 0, 1, 0, 0, 0, 0, 0, 0 + ]; + let input: Image = Image::try_create(10, 10, pixels).expect("image"); + let mut ca: CellularAutomaton<_> = CellularAutomaton::::with_image(&input, Some(0)); + + // Act + ca.step_once(); + let actual: Image = ca.current; + + // Assert + let expected_pixels: Vec = vec![ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, + 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, + 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, + 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, + 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 + ]; + let expected: Image = Image::try_create(10, 10, expected_pixels).expect("image"); + assert_eq!(actual, expected); + } + + #[test] + fn test_70000_maze() { + // Act + let pixels: Vec = vec![ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, + 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, + 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, + 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ]; + let input: Image = Image::try_create(10, 10, pixels).expect("image"); + let mut ca: CellularAutomaton<_> = CellularAutomaton::::with_image(&input, Some(0)); + + // Act + ca.step_once(); + let actual: Image = ca.current; + + // Assert + let expected_pixels: Vec = vec![ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, + 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, + 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, + 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + ]; + let expected: Image = Image::try_create(10, 10, expected_pixels).expect("image"); + assert_eq!(actual, expected); + } } diff --git a/rust_project/loda-rust-cli/src/arc/generate_dataset_gameoflife.rs b/rust_project/loda-rust-cli/src/arc/generate_dataset_gameoflife.rs index 6d230cb7..874f23e2 100644 --- a/rust_project/loda-rust-cli/src/arc/generate_dataset_gameoflife.rs +++ b/rust_project/loda-rust-cli/src/arc/generate_dataset_gameoflife.rs @@ -4,6 +4,11 @@ //! https://huggingface.co/datasets/neoneye/gameoflife-v1 //! //! Future experiments: +//! Use different symbols than only . and *. +//! Use different separator characters. Currently no separator is used. +//! Detect of what symbols are being used, so it writes that: dead=., alive=*, separator=none. +//! Do more prediction steps. Currently only 1 or 2 steps are being used. +//! //! Game of life: check for oscillators //! Game of life: recognize shapes. use super::{CellularAutomaton, cellular_automaton::rule};