allow groups to contain the void, increase search space to find matches that overlap the negative borders
This commit is contained in:
parent
ac9685b2d5
commit
4189c5188e
2 changed files with 51 additions and 39 deletions
|
@ -10,7 +10,7 @@ pub struct Cell(pub u16);
|
||||||
pub struct Dish {
|
pub struct Dish {
|
||||||
pub chunk: Chunk,
|
pub chunk: Chunk,
|
||||||
pub rules: Vec<Rule>,
|
pub rules: Vec<Rule>,
|
||||||
pub cell_groups: Vec<Vec<Cell>>,
|
pub cell_groups: Vec<Vec<Option<Cell>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -311,7 +311,7 @@ impl Dish {
|
||||||
Self {
|
Self {
|
||||||
chunk: Chunk::new().fill_random(),
|
chunk: Chunk::new().fill_random(),
|
||||||
rules: default_rules,
|
rules: default_rules,
|
||||||
cell_groups: vec![vec![Cell(0), Cell(1)]],
|
cell_groups: vec![vec![None, Some(Cell(1))]],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -325,8 +325,6 @@ impl Dish {
|
||||||
if self.rules.is_empty() {
|
if self.rules.is_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let x = random::<usize>() % CHUNK_SIZE;
|
|
||||||
let y = random::<usize>() % CHUNK_SIZE;
|
|
||||||
let enabled_rules = self
|
let enabled_rules = self
|
||||||
.rules
|
.rules
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -338,38 +336,39 @@ impl Dish {
|
||||||
}
|
}
|
||||||
let rule = random::<usize>() % enabled_rules.len();
|
let rule = random::<usize>() % enabled_rules.len();
|
||||||
let rule = enabled_rules[rule];
|
let rule = enabled_rules[rule];
|
||||||
self.fire_rule(rule, x, y);
|
self.fire_rule(rule);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fire_rule(&mut self, rule_index: usize, x: usize, y: usize) {
|
fn fire_rule(&mut self, rule_index: usize) {
|
||||||
let rule = &self.rules[rule_index];
|
let rule = &self.rules[rule_index];
|
||||||
// find matching variants
|
let variant_index = random::<usize>() % rule.variants.len();
|
||||||
let mut matching_variants = Vec::new();
|
let variant = &rule.variants[variant_index].clone();
|
||||||
for (i, v) in rule.variants.iter().enumerate() {
|
let border_x = variant.width - 1;
|
||||||
if self.subrule_matches(x, y, v) {
|
let border_y = variant.height - 1;
|
||||||
matching_variants.push(i);
|
let x = ((random::<usize>() % (CHUNK_SIZE + border_x)) as isize)
|
||||||
}
|
.wrapping_sub_unsigned(border_x);
|
||||||
}
|
let y = ((random::<usize>() % (CHUNK_SIZE + border_y)) as isize)
|
||||||
if matching_variants.is_empty() {
|
.wrapping_sub_unsigned(border_y);
|
||||||
|
|
||||||
|
if !self.subrule_matches(x, y, variant) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let variant_index = random::<usize>() % matching_variants.len();
|
|
||||||
let variant = rule.variants[matching_variants[variant_index]].clone();
|
|
||||||
|
|
||||||
let width = variant.width;
|
let width = variant.width;
|
||||||
let height = variant.height;
|
let height = variant.height;
|
||||||
let mut old_state = Vec::new();
|
let mut old_state = Vec::new();
|
||||||
for dy in 0..height {
|
for dy in 0..height {
|
||||||
for dx in 0..width {
|
for dx in 0..width {
|
||||||
old_state.push(self.get_cell(x + dx, y + dy).unwrap());
|
old_state.push(
|
||||||
|
self.get_cell((x as usize).wrapping_add(dx), (y as usize).wrapping_add(dy)),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for dx in 0..width {
|
for dx in 0..width {
|
||||||
for dy in 0..height {
|
for dy in 0..height {
|
||||||
let px = x + dx;
|
let px = x.wrapping_add_unsigned(dx) as usize;
|
||||||
let py = y + dy;
|
let py = y.wrapping_add_unsigned(dy) as usize;
|
||||||
match variant.get(dx, dy).1 {
|
match variant.get(dx, dy).1 {
|
||||||
RuleCellTo::One(rule_cell) => {
|
RuleCellTo::One(rule_cell) => {
|
||||||
self.set_cell(px, py, rule_cell.clone());
|
self.set_cell(px, py, rule_cell.clone());
|
||||||
|
@ -378,29 +377,32 @@ impl Dish {
|
||||||
let group = &self.cell_groups[group_id];
|
let group = &self.cell_groups[group_id];
|
||||||
let i = random::<usize>() % group.len();
|
let i = random::<usize>() % group.len();
|
||||||
let cell = group[i];
|
let cell = group[i];
|
||||||
|
if let Some(cell) = cell {
|
||||||
self.set_cell(px, py, cell);
|
self.set_cell(px, py, cell);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
RuleCellTo::Copy(index) => {
|
RuleCellTo::Copy(index) => {
|
||||||
let cell = old_state[index];
|
let cell = old_state[index];
|
||||||
|
if let Some(cell) = cell {
|
||||||
|
// if the copy source is outside the world, do nothing
|
||||||
self.set_cell(px, py, cell);
|
self.set_cell(px, py, cell);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
RuleCellTo::None => (),
|
RuleCellTo::None => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn subrule_matches(&self, x: usize, y: usize, subrule: &SubRule) -> bool {
|
fn subrule_matches(&self, x: isize, y: isize, subrule: &SubRule) -> bool {
|
||||||
for dx in 0..subrule.width {
|
for dx in 0..subrule.width {
|
||||||
for dy in 0..subrule.height {
|
for dy in 0..subrule.height {
|
||||||
let x = x + dx;
|
let x = x.wrapping_add_unsigned(dx) as usize;
|
||||||
let y = y + dy;
|
let y = y.wrapping_add_unsigned(dy) as usize;
|
||||||
let Some(cell) = self.get_cell(x, y) else {
|
let cell = self.get_cell(x, y);
|
||||||
return false;
|
|
||||||
};
|
|
||||||
match subrule.get(dx, dy).0 {
|
match subrule.get(dx, dy).0 {
|
||||||
RuleCellFrom::One(rule_cell) => {
|
RuleCellFrom::One(rule_cell) => {
|
||||||
if cell != rule_cell {
|
if cell != Some(rule_cell) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -143,19 +143,25 @@ impl eframe::App for UScope {
|
||||||
let (rect, _response) = ui.allocate_exact_size(Vec2::splat(CSIZE), Sense::click());
|
let (rect, _response) = ui.allocate_exact_size(Vec2::splat(CSIZE), Sense::click());
|
||||||
draw_group(ui, rect, group, &self.cell_types);
|
draw_group(ui, rect, group, &self.cell_types);
|
||||||
ui.menu_button("edit", |ui| {
|
ui.menu_button("edit", |ui| {
|
||||||
|
let mut void = group.contains(&None);
|
||||||
|
if ui.checkbox(&mut void, "void").changed() {
|
||||||
|
if void {
|
||||||
|
group.push(None);
|
||||||
|
} else {
|
||||||
|
group.retain(|c| c.is_some());
|
||||||
|
}
|
||||||
|
}
|
||||||
for (i, celldata) in self.cell_types.iter().enumerate() {
|
for (i, celldata) in self.cell_types.iter().enumerate() {
|
||||||
let mut included = group.contains(&Cell(i as u16));
|
let mut included = group.contains(&Some(Cell(i as u16)));
|
||||||
if ui.checkbox(&mut included, &celldata.name).changed() {
|
if ui.checkbox(&mut included, &celldata.name).changed() {
|
||||||
if included {
|
if included {
|
||||||
group.push(Cell(i as u16));
|
group.push(Some(Cell(i as u16)));
|
||||||
} else {
|
} else {
|
||||||
group.retain(|c| c.0 != i as u16);
|
group.retain(|c| c != &Some(Cell(i as u16)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// if response.clicked(){
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
if ui.button("add group").clicked() {
|
if ui.button("add group").clicked() {
|
||||||
self.dish.cell_groups.push(Vec::new());
|
self.dish.cell_groups.push(Vec::new());
|
||||||
|
@ -218,7 +224,7 @@ const CSIZE: f32 = 24.;
|
||||||
const RESIZE_BUTTON_WIDTH: f32 = 8.;
|
const RESIZE_BUTTON_WIDTH: f32 = 8.;
|
||||||
|
|
||||||
const OUTLINE: (f32, Color32) = (2., Color32::GRAY);
|
const OUTLINE: (f32, Color32) = (2., Color32::GRAY);
|
||||||
fn rule_editor(ui: &mut Ui, rule: &mut Rule, cells: &[CellData], groups: &[Vec<Cell>]) {
|
fn rule_editor(ui: &mut Ui, rule: &mut Rule, cells: &[CellData], groups: &[Vec<Option<Cell>>]) {
|
||||||
ui.checkbox(&mut rule.enabled, "enable rule");
|
ui.checkbox(&mut rule.enabled, "enable rule");
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.label("flip");
|
ui.label("flip");
|
||||||
|
@ -359,7 +365,7 @@ fn rule_cell_edit_from(
|
||||||
x: usize,
|
x: usize,
|
||||||
y: usize,
|
y: usize,
|
||||||
cells: &[CellData],
|
cells: &[CellData],
|
||||||
groups: &[Vec<Cell>],
|
groups: &[Vec<Option<Cell>>],
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let mut changed = false;
|
let mut changed = false;
|
||||||
let rect = Rect::from_min_size(
|
let rect = Rect::from_min_size(
|
||||||
|
@ -422,7 +428,7 @@ fn rule_cell_edit_to(
|
||||||
rule: &mut RuleCellTo,
|
rule: &mut RuleCellTo,
|
||||||
(x, y): (usize, usize),
|
(x, y): (usize, usize),
|
||||||
cells: &[CellData],
|
cells: &[CellData],
|
||||||
groups: &[Vec<Cell>],
|
groups: &[Vec<Option<Cell>>],
|
||||||
(rule_width, rule_height): (usize, usize),
|
(rule_width, rule_height): (usize, usize),
|
||||||
overlay_lines: &mut Vec<(Pos2, Pos2)>,
|
overlay_lines: &mut Vec<(Pos2, Pos2)>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
|
@ -498,15 +504,19 @@ fn rule_cell_edit_to(
|
||||||
changed
|
changed
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_group(ui: &mut Ui, rect: Rect, group: &[Cell], cells: &[CellData]) {
|
fn draw_group(ui: &mut Ui, rect: Rect, group: &[Option<Cell>], cells: &[CellData]) {
|
||||||
let group_size = group.len();
|
let group_size = group.len();
|
||||||
let radius_per_color = (CSIZE * 0.7) / (group_size as f32);
|
let radius_per_color = (CSIZE * 0.7) / (group_size as f32);
|
||||||
for (i, cell) in group.iter().enumerate() {
|
for (i, cell) in group.iter().flatten().enumerate() {
|
||||||
let color = cells[cell.id()].color;
|
let color = cells[cell.id()].color;
|
||||||
let radius = radius_per_color * ((group_size - i) as f32);
|
let radius = radius_per_color * ((group_size - i) as f32);
|
||||||
ui.painter_at(rect)
|
ui.painter_at(rect)
|
||||||
.circle_filled(rect.center(), radius, color);
|
.circle_filled(rect.center(), radius, color);
|
||||||
}
|
}
|
||||||
|
if group.contains(&None) {
|
||||||
|
ui.painter_at(rect)
|
||||||
|
.line_segment([rect.min, rect.max], (1., Color32::WHITE));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CellData {
|
impl CellData {
|
||||||
|
|
Loading…
Reference in a new issue