Skip to content
Snippets Groups Projects
Commit f358b465 authored by Finn Bear's avatar Finn Bear
Browse files

Conway WIP.

parent 92a715df
No related branches found
No related tags found
No related merge requests found
use eframe::egui::{Align2, Color32, Context, Pos2, Rect, Shape, Stroke, Ui, Vec2, Window};
use eframe::egui::{
Align2, Color32, Context, Pos2, Rect, Rounding, Shape, Stroke, Ui, Vec2, Window,
};
use eframe::emath;
use eframe::epaint::RectShape;
#[derive(Clone)]
pub struct Grid {
name: &'static str,
offset_x: f32,
offset_y: f32,
size_cells: usize,
size_pixels: f32,
stroke: Color32,
pub name: &'static str,
pub offset_x: f32,
pub offset_y: f32,
pub size_cells: usize,
pub size_pixels: f32,
pub stroke: Color32,
pub stroke_width: f32,
pub background: Color32,
fill: Vec<Color32>,
}
impl Default for Grid {
......@@ -19,11 +26,44 @@ impl Default for Grid {
size_cells: 16,
size_pixels: 400.0,
stroke: Color32::GRAY,
stroke_width: 1.0,
background: Color32::from_rgb(230, 230, 230),
fill: Vec::new(),
}
}
}
impl Grid {
fn index(&self, x: usize, y: usize) -> usize {
assert!(x < self.size_cells);
assert!(y < self.size_cells);
x + y * self.size_cells
}
pub fn fill(&self, x: usize, y: usize) -> Color32 {
self.fill
.get(self.index(x, y))
.cloned()
.unwrap_or(Color32::TRANSPARENT)
}
pub fn set_fill(&mut self, x: usize, y: usize, fill: Color32) {
let idx = self.index(x, y);
loop {
match self.fill.get_mut(idx) {
Some(f) => {
*f = fill;
return;
}
None => self.fill.push(Color32::TRANSPARENT),
}
}
}
pub fn clear_fill(&mut self) {
self.fill.clear();
}
pub fn show(&self, ctx: &Context) {
Window::new(self.name)
.title_bar(false)
......@@ -37,27 +77,55 @@ impl Grid {
rect,
);
for c in 0..=self.size_cells {
let coord = c as f32 / self.size_cells as f32;
// Horizontal.
ui.painter().add(Shape::LineSegment {
points: [
to_screen * Pos2::new(0.0, coord),
to_screen * Pos2::new(1.0, coord),
],
stroke: Stroke::new(1.0, self.stroke),
});
// Vertical.
ui.painter().add(Shape::LineSegment {
points: [
to_screen * Pos2::new(coord, 0.0),
to_screen * Pos2::new(coord, 1.0),
],
stroke: Stroke::new(1.0, self.stroke),
});
if self.background.a() > 0 {
ui.painter().add(Shape::Rect(RectShape::filled(
to_screen.transform_rect(Rect::from_x_y_ranges(0f32..=1f32, 0f32..=1f32)),
Rounding::none(),
self.background,
)));
}
for x in 0..=self.size_cells {
for y in 0..=self.size_cells {}
let cell_width = 1.0 / self.size_cells as f32;
for y in 0..self.size_cells {
let y_coord = y as f32 / self.size_cells as f32;
for x in 0..self.size_cells {
let idx = self.index(x, y);
if let Some(fill) = self.fill.get(idx) {
if fill.a() > 0 {
let x_coord = x as f32 / self.size_cells as f32;
ui.painter().add(Shape::Rect(RectShape::filled(
to_screen.transform_rect(Rect::from_x_y_ranges(
x_coord..=x_coord + cell_width,
y_coord..=y_coord + cell_width,
)),
Rounding::none(),
*fill,
)));
}
}
}
}
if self.stroke.a() > 0 && self.stroke_width > 0.0 {
for c in 0..=self.size_cells {
let coord = c as f32 / self.size_cells as f32;
// Horizontal.
ui.painter().add(Shape::LineSegment {
points: [
to_screen * Pos2::new(0.0, coord),
to_screen * Pos2::new(1.0, coord),
],
stroke: Stroke::new(self.stroke_width, self.stroke),
});
// Vertical.
ui.painter().add(Shape::LineSegment {
points: [
to_screen * Pos2::new(coord, 0.0),
to_screen * Pos2::new(coord, 1.0),
],
stroke: Stroke::new(self.stroke_width, self.stroke),
});
}
}
});
}
......
#[derive(Default)]
pub struct Governor {
last: f64,
}
impl Governor {
pub fn ready(&mut self, time: f64, limit: f64) -> bool {
if time > self.last + limit {
self.last = time;
true
} else {
false
}
}
}
#![feature(derive_default_enum)]
#![feature(mixed_integer_ops)]
pub mod component;
pub mod governor;
pub mod image;
pub mod slide;
......@@ -103,14 +105,14 @@ impl epi::App for Cartoon {
});
*/
let advance = ctx.input().key_pressed(Key::Space)
|| ctx.input().key_pressed(Key::ArrowRight)
|| ctx.input().key_pressed(Key::D);
let force_advance =
ctx.input().key_pressed(Key::ArrowRight) || ctx.input().key_pressed(Key::D);
let advance = force_advance || ctx.input().key_pressed(Key::Space);
let retreat = ctx.input().key_pressed(Key::ArrowLeft) || ctx.input().key_pressed(Key::A);
if advance || retreat {
self.slide_index = if advance {
if self.slides[self.slide_index].transition(ctx) {
if force_advance || self.slides[self.slide_index].transition(ctx) {
let new = (self.slide_index + 1) % self.slides.len();
if new == 0 {
self.slides = create_slides();
......
......@@ -3,19 +3,33 @@ use eframe::egui::{Context, Frame, Ui};
use eframe::{egui, epi};
#[derive(Default)]
pub struct Introduction {}
pub struct Introduction {
strengths: bool,
}
impl Slide for Introduction {
fn transition(&mut self, ctx: &Context) -> bool {
let done = self.strengths;
self.strengths = true;
done
}
fn show(&mut self, ui: &mut Ui, _ctx: &Context) {
Frame::none().margin(Margin::same(20.0)).show(ui, |ui| {
ui.heading("Introduction");
ui.heading("Introduction to Artistic Algorithms");
ui.add_space(8.0);
ui.label("Weaknesses");
ui.small(" ✖ Blah");
ui.small(" ✖ Blah");
ui.add_space(10.0);
ui.label("Strengths");
ui.small(" ✔ Blah");
ui.small(" ✖ Social context");
ui.small(" ✖ Human emotion");
ui.small(" ✖ Political commentary");
if self.strengths {
ui.add_space(10.0);
ui.label("Strengths");
ui.small(" ✔ Following rules");
ui.small(" ✔ Performing computation");
ui.small(" ✔ Harnessing chaos and randomness");
ui.small(" ✔ Guided exploration");
}
});
}
}
use crate::component::grid::Grid;
use crate::governor::Governor;
use crate::Slide;
use eframe::egui::style::Margin;
use eframe::egui::{Align2, Color32, Context, Frame, Pos2, Rect, Shape, Stroke, Ui, Vec2, Window};
use eframe::emath;
use rand::Rng;
#[derive(Default)]
pub struct Conway {
life: Grid,
governor: Governor,
}
impl Default for Conway {
fn default() -> Self {
let mut life = Grid::default();
for y in 0..life.size_cells {
for x in 0..life.size_cells {
if rand::thread_rng().gen_bool(0.5) {
life.set_fill(x, y, Color32::BLACK);
}
}
}
/*
life.clear_fill();
life.set_fill(5, 5, Color32::BLACK);
life.set_fill(6, 5, Color32::BLACK);
life.set_fill(7, 5, Color32::BLACK);
*/
Self {
life,
governor: Governor::default(),
}
}
}
impl Slide for Conway {
fn show(&mut self, ui: &mut Ui, ctx: &Context) {
Frame::none().margin(Margin::same(20.0)).show(ui, |ui| {
ui.vertical_centered(|ui| {
ui.heading("Cellular Automata");
});
});
ctx.request_repaint();
if self.governor.ready(ctx.input().time, 0.2) {
self.life = conway(&self.life);
}
self.life.show(ctx);
}
}
fn conway(grid: &Grid) -> Grid {
let mut new = grid.clone();
new.clear_fill();
for cy in 0..grid.size_cells {
for cx in 0..grid.size_cells {
let mut neighbors = 0;
for dy in -1..=1 {
for dx in -1..=1 {
let (x, y) = match (cx.checked_add_signed(dx), cy.checked_add_signed(dy)) {
(Some(x), Some(y)) if x < grid.size_cells && y < grid.size_cells => (x, y),
_ => continue,
};
if x == cx && y == cy {
// Don't consider self.
continue;
}
if grid.fill(x, y).a() > 0 {
neighbors += 1;
}
}
}
let mut alive = grid.fill(cx, cy).a() > 0;
alive = match (alive, neighbors) {
(false, 3) => true,
(false, _) => false,
(true, 2) | (true, 3) => true,
(true, _) => false,
};
new.set_fill(
cx,
cy,
if alive {
Color32::BLACK
} else {
Color32::TRANSPARENT
},
);
}
}
new
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment