subplate works

This commit is contained in:
2026-06-18 20:51:09 +03:00
parent 4b43f43c75
commit 0ab895f79e
7 changed files with 285 additions and 42 deletions
Generated
+40
View File
@@ -2127,6 +2127,25 @@ dependencies = [
"crossbeam-utils",
]
[[package]]
name = "crossbeam-deque"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
dependencies = [
"crossbeam-epoch",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
dependencies = [
"crossbeam-utils",
]
[[package]]
name = "crossbeam-queue"
version = "0.3.12"
@@ -4098,6 +4117,26 @@ version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539"
[[package]]
name = "rayon"
version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d"
dependencies = [
"either",
"rayon-core",
]
[[package]]
name = "rayon-core"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91"
dependencies = [
"crossbeam-deque",
"crossbeam-utils",
]
[[package]]
name = "read-fonts"
version = "0.36.0"
@@ -4607,6 +4646,7 @@ dependencies = [
"bevy",
"rand 0.10.1",
"rand_chacha 0.10.0",
"rayon",
]
[[package]]
+1
View File
@@ -7,3 +7,4 @@ edition = "2024"
bevy = { version = "0.18.1", features = ["keyboard"] }
rand = "0.10.1"
rand_chacha = "0.10.0"
rayon = "1.12.0"
+36 -2
View File
@@ -30,7 +30,7 @@ impl<T: Clone> Table<T> {
&self.data[index]
}
fn get_dim(&mut self, x: usize, y: usize) -> &T {
fn get_dim(&self, x: usize, y: usize) -> &T {
self.get(x + y * self.side)
}
@@ -60,7 +60,7 @@ impl<T: Clone> Table<T> {
self.side = new_side;
}
pub fn iter(&self) -> impl Iterator<Item = &T> {
pub fn iter(&self) -> impl Iterator<Item=&T> {
self.data.iter()
}
@@ -69,6 +69,23 @@ impl<T: Clone> Table<T> {
table.data[i] = f(self[i].clone())
}
}
pub fn around_line(&self, index: usize) -> Vec<&T> {
self.around(index % self.side, index / self.side)
}
pub fn around(&self, x: usize, y: usize) -> Vec<&T> {
let coordinates = vec![
(x as isize, y as isize - 1),
(x as isize, y as isize + 1),
(x as isize + 1, y as isize),
(x as isize - 1, y as isize),
];
coordinates.iter().filter(|(x, y)| {
*x >= 0 && *x < self.side as isize && *y >= 0 && *y < self.side as isize
}).map(|(x, y)| self.get_dim(*x as usize, *y as usize)).collect::<Vec<_>>()
}
}
impl<T: Clone> Into<Vec<T>> for Table<T> {
@@ -99,6 +116,23 @@ impl IntoImage for Table<bool> {
data
}
}
impl IntoImage for Table<Color> {
fn get_image_data(&self) -> Vec<u8> {
let mut data: Vec<u8> = vec![0; self.side * self.side * 4];
self.data
.iter()
.zip((0..self.data.len()).collect::<Vec<_>>())
.for_each(|(color, idx)| {
let idx = idx * 4;
let color = color.to_linear();
data[idx] = (color.red * 255.0) as u8;
data[idx + 1] = (color.green * 255.0) as u8;
data[idx + 2] = (color.blue * 255.0) as u8;
data[idx + 3] = 255;
});
data
}
}
impl<T: Clone> Index<usize> for Table<T> {
type Output = T;
+63 -29
View File
@@ -1,28 +1,38 @@
mod basic;
mod seed_automation;
mod plate_automation;
mod subplate_automation;
use crate::basic::{IntoImage, Table};
use bevy::asset::io::embedded::GetAssetServer;
use bevy::input::keyboard::keyboard_input_system;
use bevy::prelude::*;
use bevy::window::{ExitCondition, WindowResolution};
use rand::{Rng, RngExt};
use rand_chacha::ChaCha8Rng;
use rand_chacha::rand_core::SeedableRng;
use seed_automation::SeedAutomation;
const RECTANGLE_SIDE: f32 = 500.0;
const RECTANGLE_SIDE: f32 = 750.0;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(DefaultPlugins.set(WindowPlugin {
primary_window: Some(Window {
title: "Automations".into(),
resolution: WindowResolution::new(RECTANGLE_SIDE as u32, RECTANGLE_SIDE as u32),
..default()
}),
..default()
}))
.add_systems(Startup, setup)
.insert_resource(Time::<Fixed>::from_hz(1024.0))
// .add_systems(Update, automation_keyboard_input_system)
.add_systems(Update, seed_automation::update_automation_seed)
.add_systems(Update, seed_automation::update_automation_view_seed)
.add_systems(Update, plate_automation::update_automation_plate)
.add_systems(Update, plate_automation::update_automation_view_plate)
.add_systems(Update, seed_automation::update_automation)
.add_systems(Update, seed_automation::update_automation_view)
.add_systems(Update, plate_automation::update_automation)
.add_systems(Update, plate_automation::update_automation_view)
.add_systems(Update, subplate_automation::update_automation)
.add_systems(Update, subplate_automation::update_automation_view)
.run();
}
@@ -44,27 +54,51 @@ fn setup(mut commands: Commands, mut images: ResMut<Assets<Image>>) {
commands.insert_resource(SeededRng(seeded_rng));
}
// fn automation_keyboard_input_system(keys: Res<ButtonInput<KeyCode>>, mut commands: Commands) {
// if keys.just_pressed(KeyCode::Space) {
// commands.spawn((AutomationNext,));
// }
//
// if keys.just_pressed(KeyCode::Tab) {
// commands.spawn((AutomationMigrate,));
// }
//
// if keys.just_pressed(KeyCode::AltLeft) {
// commands.spawn((AutomationScale,));
// }
// }
//
// #[derive(Component)]
// struct AutomationNext;
//
// #[derive(Component)]
// struct AutomationScale;
//
// #[derive(Component)]
// struct AutomationMigrate;
#[derive(Resource)]
struct SeededRng(ChaCha8Rng);
#[cfg(test)]
mod tests {
use crate::basic::Table;
#[test]
fn around_1(){
let mut table = Table::new(false, 16);
let around = table.around(0, 0);
assert_eq!(around.len(), 2);
}
#[test]
fn around_2(){
let mut table = Table::new(false, 16);
let around = table.around(15, 15);
assert_eq!(around.len(), 2);
}
#[test]
fn around_3(){
let mut table = Table::new(false, 16);
let around = table.around(5, 5);
assert_eq!(around.len(), 4);
}
#[test]
fn around_1_line(){
let mut table = Table::new(false, 16);
let around = table.around_line(0);
assert_eq!(around.len(), 2);
}
#[test]
fn around_2_line(){
let mut table = Table::new(false, 16);
let around = table.around_line(16 * 16 - 1);
assert_eq!(around.len(), 2);
}
#[test]
fn around_3_line(){
let mut table = Table::new(false, 16);
let around = table.around_line(24);
assert_eq!(around.len(), 4);
}
}
+35 -7
View File
@@ -3,12 +3,14 @@ use crate::basic::{IntoImage, Table};
use bevy::asset::{Assets, RenderAssetUsages};
use bevy::image::{BevyDefault, Image};
use bevy::input::ButtonInput;
use bevy::prelude::{Component, KeyCode, Query, Res, ResMut, Sprite};
use bevy::prelude::{Color, Commands, Component, Entity, KeyCode, Query, Res, ResMut, Sprite};
use bevy::render::render_resource::{Extent3d, TextureDimension, TextureFormat};
use rand::RngExt;
use rand_chacha::ChaCha8Rng;
use crate::seed_automation::SeedAutomation;
use crate::subplate_automation::SubPlateAutomation;
pub fn update_automation_view_plate(
pub fn update_automation_view(
query: Query<(&Sprite, &PlateAutomation)>,
mut images: ResMut<Assets<Image>>,
) {
@@ -34,17 +36,18 @@ pub fn update_automation_view_plate(
images.insert(sprite.image.id(), image).unwrap();
}
pub fn update_automation_plate(
mut query: Query<&mut PlateAutomation>,
pub fn update_automation(
mut query: Query<(&mut PlateAutomation, Entity)>,
mut seeded_rng: ResMut<SeededRng>,
keys: Res<ButtonInput<KeyCode>>,
mut commands: Commands,
) {
if query.is_empty() {
return;
}
let mut automation = query.iter_mut().next().unwrap();
if keys.just_pressed(KeyCode::Space) {
let (mut automation, entity) = query.iter_mut().next().unwrap();
if keys.just_pressed(KeyCode::Space) || keys.all_pressed([KeyCode::Space, KeyCode::ShiftLeft]) {
let random = &mut seeded_rng.0;
automation.next(random)
@@ -53,6 +56,15 @@ pub fn update_automation_plate(
if keys.just_pressed(KeyCode::AltLeft) {
automation.world.grow()
}
if keys.just_pressed(KeyCode::Tab) {
println!("Switching to SubPlateAutomation");
let mut new_table = Table::<Color>::new(Color::BLACK, automation.world.side);
automation.world.convert_copy(&mut new_table, |value| { if value { Color::WHITE } else { Color::BLACK } });
commands.entity(entity).remove::<PlateAutomation>().insert(SubPlateAutomation{
world: new_table
});
}
}
#[derive(Component)]
@@ -62,6 +74,22 @@ pub struct PlateAutomation {
impl PlateAutomation {
fn next(&mut self, rng: &mut ChaCha8Rng) {
println!("Next for plate automation");
for index in 0..self.world.side * self.world.side {
if *self.world.get(index) {
continue;
}
let around = self.world.around_line(index).iter().filter(|v| ***v).count();
if around == 0 {
continue;
}
let chance = (around as f32 * 0.2).powi(2);
if rng.random::<f32>() > chance {
continue;
}
self.world.set(index, true);
}
}
}
+2 -2
View File
@@ -9,7 +9,7 @@ use rand::RngExt;
use rand_chacha::ChaCha8Rng;
use crate::plate_automation::PlateAutomation;
pub fn update_automation_view_seed(
pub fn update_automation_view(
query: Query<(&Sprite, &SeedAutomation)>,
mut images: ResMut<Assets<Image>>,
) {
@@ -36,7 +36,7 @@ pub fn update_automation_view_seed(
images.insert(sprite.image.id(), image).unwrap();
}
pub fn update_automation_seed(
pub fn update_automation(
mut query: Query<(&mut SeedAutomation, Entity)>,
mut seeded_rng: ResMut<SeededRng>,
keys: Res<ButtonInput<KeyCode>>,
+106
View File
@@ -0,0 +1,106 @@
use crate::SeededRng;
use crate::basic::{IntoImage, Table};
use bevy::asset::{Assets, RenderAssetUsages};
use bevy::image::{BevyDefault, Image};
use bevy::input::ButtonInput;
use bevy::prelude::{Color, Commands, Component, Entity, KeyCode, Query, Res, ResMut, Sprite};
use bevy::render::render_resource::{Extent3d, TextureDimension, TextureFormat};
use rand::{ RngExt};
use rand_chacha::ChaCha8Rng;
pub fn update_automation_view(
query: Query<(&Sprite, &SubPlateAutomation)>,
mut images: ResMut<Assets<Image>>,
) {
if query.is_empty() {
return;
}
let (sprite, automation) = query.iter().next().unwrap();
let size = automation.world.side as u32;
let data = automation.world.get_image_data();
let image = Image::new(
Extent3d {
width: size,
height: size,
depth_or_array_layers: 1,
},
TextureDimension::D2,
data,
TextureFormat::bevy_default(),
RenderAssetUsages::default(),
);
images.remove(sprite.image.id());
images.insert(sprite.image.id(), image).unwrap();
}
pub fn update_automation(
mut query: Query<(&mut SubPlateAutomation, Entity)>,
mut seeded_rng: ResMut<SeededRng>,
keys: Res<ButtonInput<KeyCode>>,
commands: Commands,
) {
if query.is_empty() {
return;
}
let (mut automation, entity) = query.iter_mut().next().unwrap();
if keys.just_pressed(KeyCode::Space) || keys.all_pressed([KeyCode::Space, KeyCode::ShiftLeft]) {
let random = &mut seeded_rng.0;
automation.next(random)
}
if keys.just_pressed(KeyCode::AltLeft) {
let random = &mut seeded_rng.0;
automation.seed(random);
}
if keys.just_pressed(KeyCode::Tab) {
}
}
#[derive(Component)]
pub struct SubPlateAutomation {
pub(crate) world: Table<Color>,
}
impl SubPlateAutomation {
fn next(&mut self, rng: &mut ChaCha8Rng) {
for index in 0..self.world.side * self.world.side {
let current_color = *self.world.get(index);
if current_color == Color::BLACK || current_color != Color::WHITE {
continue;
}
if rng.random::<f32>() < 0.7 {
continue;
}
let around = self.world.around_line(index).iter().filter(|v| ***v != Color::WHITE && ***v != Color::BLACK).map(|color| (*color).clone()).collect::<Vec<_>>();
if around.len() == 0 {
continue;
}
let color = around[rng.random_range(0..around.len())];
self.world.set(index, color);
}
}
fn seed(&mut self, rng: &mut ChaCha8Rng){
let len = (self.world.side * self.world.side) as f32;
loop {
let index = (rng.random::<f32>() * len) as usize;
if *self.world.get(index) == Color::BLACK {
continue;
}
self.world.set(index, Color::hsv(rng.random::<f32>() * 360.0, 1.0, 1.0));
break;
}
}
}