Compare commits
2 commits
5af7cc0cb1
...
4d61184edd
Author | SHA1 | Date | |
---|---|---|---|
4d61184edd | |||
ef14cef49b |
2 changed files with 62 additions and 47 deletions
|
@ -10,7 +10,14 @@ 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<Option<Cell>>>,
|
pub cell_groups: Vec<CellGroup>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||||
|
pub struct CellGroup {
|
||||||
|
pub name: String,
|
||||||
|
pub void: bool,
|
||||||
|
pub cells: Vec<Cell>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -26,12 +33,11 @@ pub struct Rule {
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
variants: Vec<SubRule>,
|
variants: Vec<SubRule>,
|
||||||
pub enabled: bool,
|
pub enabled: bool,
|
||||||
// probability: u8
|
|
||||||
#[serde(alias = "flip_h")]
|
|
||||||
pub flip_x: bool,
|
pub flip_x: bool,
|
||||||
#[serde(alias = "flip_v")]
|
|
||||||
pub flip_y: bool,
|
pub flip_y: bool,
|
||||||
pub rotate: bool,
|
pub rotate: bool,
|
||||||
|
#[serde(default)]
|
||||||
|
pub failrate: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
|
@ -126,6 +132,7 @@ impl Rule {
|
||||||
flip_x: false,
|
flip_x: false,
|
||||||
flip_y: false,
|
flip_y: false,
|
||||||
rotate: false,
|
rotate: false,
|
||||||
|
failrate: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -331,7 +338,11 @@ impl Dish {
|
||||||
Self {
|
Self {
|
||||||
chunk: Chunk::new().fill_random(),
|
chunk: Chunk::new().fill_random(),
|
||||||
rules: default_rules,
|
rules: default_rules,
|
||||||
cell_groups: vec![vec![None, Some(Cell(1))]],
|
cell_groups: vec![CellGroup {
|
||||||
|
name: "empty".into(),
|
||||||
|
void: true,
|
||||||
|
cells: vec![Cell(0)],
|
||||||
|
}],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -374,6 +385,11 @@ impl Dish {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let fail: u8 = random();
|
||||||
|
if rule.failrate > fail {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
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();
|
||||||
|
@ -395,12 +411,10 @@ impl Dish {
|
||||||
}
|
}
|
||||||
RuleCellTo::GroupRandom(group_id) => {
|
RuleCellTo::GroupRandom(group_id) => {
|
||||||
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.cells.len();
|
||||||
let cell = group[i];
|
let cell = group.cells[i];
|
||||||
if let Some(cell) = cell {
|
|
||||||
self.set_cell(px, py, cell);
|
self.set_cell(px, py, cell);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
RuleCellTo::Copy(x, y) => {
|
RuleCellTo::Copy(x, y) => {
|
||||||
let cell = old_state[x + y * variant.width];
|
let cell = old_state[x + y * variant.width];
|
||||||
if let Some(cell) = cell {
|
if let Some(cell) = cell {
|
||||||
|
@ -427,7 +441,12 @@ impl Dish {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RuleCellFrom::Group(group_id) => {
|
RuleCellFrom::Group(group_id) => {
|
||||||
if !self.cell_groups[group_id].contains(&cell) {
|
let group = &self.cell_groups[group_id];
|
||||||
|
if let Some(cell) = cell {
|
||||||
|
if !group.cells.contains(&cell) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if !group.void {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,12 +10,12 @@ use eframe::{
|
||||||
epaint::Hsva,
|
epaint::Hsva,
|
||||||
NativeOptions,
|
NativeOptions,
|
||||||
};
|
};
|
||||||
use egui::{collapsing_header::CollapsingState, PointerButton};
|
use egui::{collapsing_header::CollapsingState, DragValue, PointerButton};
|
||||||
use native_dialog::FileDialog;
|
use native_dialog::FileDialog;
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use petri::{Cell, Chunk, Dish, Rule, RuleCellFrom, RuleCellTo, CHUNK_SIZE};
|
use petri::{Cell, CellGroup, Chunk, Dish, Rule, RuleCellFrom, RuleCellTo, CHUNK_SIZE};
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -147,29 +147,25 @@ impl eframe::App for UScope {
|
||||||
let (rect, _response) =
|
let (rect, _response) =
|
||||||
ui.allocate_exact_size(Vec2::splat(CSIZE), Sense::click());
|
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.horizontal(|ui| {
|
||||||
ui.menu_button("edit", |ui| {
|
ui.menu_button("edit", |ui| {
|
||||||
let mut void = group.contains(&None);
|
ui.checkbox(&mut group.void, "void");
|
||||||
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(&Some(Cell(i as u16)));
|
let mut included = group.cells.contains(&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(Some(Cell(i as u16)));
|
group.cells.push(Cell(i as u16));
|
||||||
} else {
|
} else {
|
||||||
group.retain(|c| c != &Some(Cell(i as u16)));
|
group.cells.retain(|c| c != &Cell(i as u16));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
ui.text_edit_singleline(&mut group.name);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if ui.button("add group").clicked() {
|
if ui.button("add group").clicked() {
|
||||||
self.dish.cell_groups.push(Vec::new());
|
self.dish.cell_groups.push(CellGroup::default());
|
||||||
}
|
}
|
||||||
|
|
||||||
ui.heading("Rules");
|
ui.heading("Rules");
|
||||||
|
@ -177,7 +173,6 @@ impl eframe::App for UScope {
|
||||||
let mut to_remove = None;
|
let mut to_remove = None;
|
||||||
let mut to_clone = None;
|
let mut to_clone = None;
|
||||||
for (i, rule) in self.dish.rules.iter_mut().enumerate() {
|
for (i, rule) in self.dish.rules.iter_mut().enumerate() {
|
||||||
// ui.separator();
|
|
||||||
rule_editor(
|
rule_editor(
|
||||||
ui,
|
ui,
|
||||||
rule,
|
rule,
|
||||||
|
@ -252,7 +247,7 @@ fn rule_editor(
|
||||||
rule: &mut Rule,
|
rule: &mut Rule,
|
||||||
index: usize,
|
index: usize,
|
||||||
cells: &[CellData],
|
cells: &[CellData],
|
||||||
groups: &[Vec<Option<Cell>>],
|
groups: &[CellGroup],
|
||||||
to_remove: &mut Option<usize>,
|
to_remove: &mut Option<usize>,
|
||||||
to_clone: &mut Option<usize>,
|
to_clone: &mut Option<usize>,
|
||||||
) {
|
) {
|
||||||
|
@ -277,10 +272,13 @@ fn rule_editor(
|
||||||
rule.generate_variants();
|
rule.generate_variants();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
ui.horizontal(|ui| {
|
||||||
if ui.checkbox(&mut rule.rotate, "rotate").changed() {
|
if ui.checkbox(&mut rule.rotate, "rotate").changed() {
|
||||||
rule.generate_variants();
|
rule.generate_variants();
|
||||||
}
|
}
|
||||||
|
ui.label("fail rate");
|
||||||
|
ui.add(DragValue::new(&mut rule.failrate));
|
||||||
|
});
|
||||||
let cells_y = rule.height();
|
let cells_y = rule.height();
|
||||||
let cells_x = rule.width();
|
let cells_x = rule.width();
|
||||||
let patt_width = CSIZE * cells_x as f32;
|
let patt_width = CSIZE * cells_x as f32;
|
||||||
|
@ -408,7 +406,7 @@ fn rule_cell_edit_from(
|
||||||
x: usize,
|
x: usize,
|
||||||
y: usize,
|
y: usize,
|
||||||
cells: &[CellData],
|
cells: &[CellData],
|
||||||
groups: &[Vec<Option<Cell>>],
|
groups: &[CellGroup],
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let mut changed = false;
|
let mut changed = false;
|
||||||
let rect = Rect::from_min_size(
|
let rect = Rect::from_min_size(
|
||||||
|
@ -471,7 +469,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<Option<Cell>>],
|
groups: &[CellGroup],
|
||||||
(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 {
|
||||||
|
@ -552,23 +550,21 @@ fn rule_cell_edit_to(
|
||||||
changed
|
changed
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_group(ui: &mut Ui, rect: Rect, group: &[Option<Cell>], cells: &[CellData]) {
|
fn draw_group(ui: &mut Ui, rect: Rect, group: &CellGroup, cells: &[CellData]) {
|
||||||
let mut group_size = group.len();
|
let group_size = group.cells.len();
|
||||||
let has_void = group.contains(&None);
|
|
||||||
if has_void {
|
|
||||||
group_size -= 1;
|
|
||||||
}
|
|
||||||
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().flatten().enumerate() {
|
for (i, cell) in group.cells.iter().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 has_void {
|
if group.void {
|
||||||
ui.painter_at(rect)
|
ui.painter_at(rect)
|
||||||
.line_segment([rect.min, rect.max], (1., Color32::WHITE));
|
.line_segment([rect.min, rect.max], (1., Color32::WHITE));
|
||||||
}
|
}
|
||||||
|
ui.allocate_rect(rect, Sense::hover())
|
||||||
|
.on_hover_text(&group.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CellData {
|
impl CellData {
|
||||||
|
|
Loading…
Reference in a new issue