diff options
-rw-r--r-- | src/ctx.rs | 76 | ||||
-rw-r--r-- | src/main.rs | 10 | ||||
-rw-r--r-- | src/quad.rs | 30 | ||||
-rw-r--r-- | src/step.rs | 7 |
4 files changed, 90 insertions, 33 deletions
@@ -1,32 +1,74 @@ use std::marker::PhantomData; use crate::quad::{Quad, Node, Embed}; +pub trait Approx<A: Embed, B: Embed, S>: Default { + fn color_base(state: &mut S, base: A) -> [u8; 4]; + + fn compress_node(state: &mut S, compr: [B; 4]) -> B; + fn expand_node(state: &mut S, compr: B) -> [B; 4]; + + fn compress_base(state: &mut S, embed: A) -> B; + fn expand_base(state: &mut S, compr: B) -> A; +} + +#[derive(Default)] +pub struct Basic; + +impl Approx<u8, u8, ()> for Basic { + fn color_base(state: &mut (), base: u8) -> [u8; 4] { + [base;4] + } + + fn compress_node(state: &mut (), c: [u8; 4]) -> u8 { + c[0]/4 + c[1]/4 + c[2]/4 + c[3]/4 + } + + fn expand_node(state: &mut (), compr: u8) -> [u8; 4] { + [compr;4] + } + + fn compress_base(state: &mut (), embed: u8) -> u8 { + embed + } + + fn expand_base(state: &mut (), compr: u8) -> u8 { + compr + } +} + /// Represents a context with shared state. -#[derive(Default, Debug)] -pub struct Ctx<A: Embed, B: Embed> { +#[derive(Debug)] +pub struct Ctx<A: Embed, B: Embed, S, N: Approx<A, B, S>> { _phantom_a: PhantomData<A>, _phantom_b: PhantomData<B>, + state: S, + networks: N, } -impl<A: Embed, B: Embed> Ctx<A, B> { +impl<A: Embed, B: Embed, S, N: Approx<A, B, S>> Ctx<A, B, S, N> { /// Creates a new uninitialized context. - pub fn new_empty() -> Self { - Default::default() + pub fn new(state: S, networks: N) -> Self { + Ctx { + _phantom_a: PhantomData, + _phantom_b: PhantomData, + state, + networks, + } } - /// Combines 4 child node representations into a single representation - /// Using a neural network. - pub fn combine(&mut self, compr: [B; 4]) -> B { - todo!("Build new B from 4 child B"); + pub fn color_base(&mut self, base: A) -> [u8; 4] { + N::color_base(&mut self.state, base) } /// Compresses a base-level cell into a vector. pub fn compress_base(&mut self, base: A) -> B { - todo!("Turn Base Cell into a vector B"); + N::compress_base(&mut self.state, base) } - pub fn color_base(&mut self, base: &A) -> [u8; 4] { - todo!(); + /// Combines 4 child node representations into a single representation + /// Using a neural network. + pub fn compress_node(&mut self, compr: [B; 4]) -> B { + N::compress_node(&mut self.state, compr) } /// Compresses a single node into a vector representation. @@ -36,7 +78,7 @@ impl<A: Embed, B: Embed> Ctx<A, B> { match quad { Quad::Base(b) => Some(self.compress_base(*b)), Quad::Node(n) => Some( - self.combine([ + self.compress_node([ n[0].compr, n[1].compr, n[2].compr, @@ -48,12 +90,12 @@ impl<A: Embed, B: Embed> Ctx<A, B> { } /// Compresses a base-level cell into a vector. - fn expand_base(&mut self, compr: B) -> A { - todo!("Turn compressed B into the A that made it"); + pub fn expand_base(&mut self, compr: B) -> A { + N::expand_base(&mut self.state, compr) } - fn expand_node(&mut self, compr: B) -> [B; 4] { - todo!("Turn compressed B into 4 child B that made it"); + pub fn expand_node(&mut self, compr: B) -> [B; 4] { + N::expand_node(&mut self.state, compr) } /// Expands the compressed representation of a node into a node with 4 children. diff --git a/src/main.rs b/src/main.rs index 3078f49..6134893 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,9 +6,15 @@ mod render; fn main() { println!("Warming up..."); - let mut ctx = ctx::Ctx::new_empty(); + let mut ctx = ctx::Ctx::new((), ctx::Basic); + + let mut base = vec![]; + for i in 0..16 { + base.push(i); + } + let quad: quad::Node<u8, u8> = quad::Node::new_from_square( - &mut ctx, vec![0xFF;64], + &mut ctx, base, ); // render::graphics(); diff --git a/src/quad.rs b/src/quad.rs index 2eb23b1..0ce8b58 100644 --- a/src/quad.rs +++ b/src/quad.rs @@ -1,7 +1,7 @@ -use crate::ctx::Ctx; +use crate::ctx::{Ctx, Approx}; pub trait Embed: Default + Copy + Sized + std::fmt::Debug { - + } /// Represents the data present in a quad-tree node. @@ -32,7 +32,12 @@ pub struct Node<A: Embed, B: Embed> { } impl<A: Embed, B: Embed> Node<A, B> { - pub fn sample_color(self, ctx: &mut Ctx<A, B>, x: isize, y: isize) -> (Self, [u8; 4]) { + pub fn sample_color<S, N: Approx<A, B, S>>( + self, + ctx: &mut Ctx<A, B, S, N>, + x: isize, + y: isize, + ) -> (Self, [u8; 4]) { // self = ctx.expand(self); // if let Quad::Base(b) = self.data { // return (self, ctx.color_base(&b)); @@ -54,12 +59,12 @@ impl<A: Embed, B: Embed> Node<A, B> { } /// Creates a new tree with a single empty base node - pub fn new_empty(ctx: &mut Ctx<A, B>) -> Self { + pub fn new_empty<S, N: Approx<A, B, S>>(ctx: &mut Ctx<A, B, S, N>) -> Self { Self::new_base(ctx, Default::default()) } /// Creates a new tree from a single base node - pub fn new_base(ctx: &mut Ctx<A, B>, base: A) -> Self { + pub fn new_base<S, N: Approx<A, B, S>>(ctx: &mut Ctx<A, B, S, N>, base: A) -> Self { Node { depth: 0, compr: ctx.compress_base(base), @@ -67,7 +72,7 @@ impl<A: Embed, B: Embed> Node<A, B> { } } - pub fn new_node(ctx: &mut Ctx<A, B>, children: [Node<A, B>;4]) -> Self { + pub fn new_node<S, N: Approx<A, B, S>>(ctx: &mut Ctx<A, B, S, N>, children: [Node<A, B>;4]) -> Self { // Make sure the depths check out assert_eq!(children[0].depth, children[1].depth); assert_eq!(children[1].depth, children[2].depth); @@ -88,8 +93,8 @@ impl<A: Embed, B: Embed> Node<A, B> { } } - fn build_square( - ctx: &mut Ctx<A, B>, + fn build_square<S, N: Approx<A, B, S>>( + ctx: &mut Ctx<A, B, S, N>, square: &[A], abs_size: usize, depth: usize, @@ -106,16 +111,17 @@ impl<A: Embed, B: Embed> Node<A, B> { let half = size / 2; // in a z-like pattern let children = [ - Self::build_square(ctx, square, abs_size, depth - 1, x + half, y ), Self::build_square(ctx, square, abs_size, depth - 1, x , y ), - Self::build_square(ctx, square, abs_size, depth - 1, x + half, y + half), + Self::build_square(ctx, square, abs_size, depth - 1, x + half, y ), Self::build_square(ctx, square, abs_size, depth - 1, x , y + half), + Self::build_square(ctx, square, abs_size, depth - 1, x + half, y + half), + ]; Self::new_node(ctx, children) } } - pub fn new_from_square(ctx: &mut Ctx<A, B>, square: Vec<A>) -> Self { + pub fn new_from_square<S, N: Approx<A, B, S>>(ctx: &mut Ctx<A, B, S, N>, square: Vec<A>) -> Self { // get the side length, ensure this is a pow2 square let area = square.len(); let size = ((area as f64).sqrt() + 0.5) as usize; @@ -135,7 +141,7 @@ impl<A: Embed, B: Embed> Node<A, B> { /// Creates a new node double the size by centering the current node /// on a node double the size. - pub fn pad_empty(self, ctx: &mut Ctx<A, B>) -> Self { + pub fn pad_empty<S, N: Approx<A, B, S>>(self, ctx: &mut Ctx<A, B, S, N>) -> Self { todo!() } } diff --git a/src/step.rs b/src/step.rs index 7010bd9..35d4328 100644 --- a/src/step.rs +++ b/src/step.rs @@ -1,7 +1,10 @@ -use crate::ctx::Ctx; +use crate::ctx::{Ctx, Approx}; use crate::quad::{Node, Embed}; -pub fn step<A: Embed, B: Embed>(ctx: &mut Ctx<A, B>, node: Node<A, B>) -> Node<A, B> { +pub fn step<A: Embed, B: Embed, S, N: Approx<A, B, S>>( + ctx: &mut Ctx<A, B, S, N>, + node: Node<A, B> +) -> Node<A, B> { // pad the graph if needed. // if we're at the base, run the cellular automation rule: |