use std::f64; use std::fs::copy; use std::fs::File; use std::io::prelude::*; use std::char::from_u32; use uuid::Uuid; use rand::prelude::*; use rand::distributions::{Normal, WeightedIndex}; use failure::Error; use failure::err_msg; pub fn molecular_write(id: Uuid) -> Result { let mut rng = thread_rng(); for _i in 0..100 { let mol: u32 = rng.gen_range(0, 10000); let src = format!("/var/lib/mnml/data/molecules/{}.svg", mol); let dest = format!("/var/lib/mnml/public/imgs/{}.svg", id); debug!("molecule src={:?}", src); debug!("molecule dest={:?}", dest); if let Ok(_bytes) = copy(&src, &dest) { info!("new molecule img generated src={:?} dest={:?}", src, dest); return Ok(id); } } return Err(err_msg("too many missing molecules. wrong directory?")) } pub fn invader_write(id: Uuid) -> Result { let mut rng = thread_rng(); let mut svg = Vec::new(); // rounding ? // filters ? // distribution for lightness // bellcurve around 75% let l_dist = Normal::new(75.0, 10.0); let s_dist = Normal::new(25.0, 10.0); let mut colours = std::iter ::repeat_with(|| { let h = rng.gen_range(0, 360); let s = s_dist.sample(&mut rng) as usize; let l = l_dist.sample(&mut rng) as usize; format!("hsl({:}, {:}%, {:}%)", h, s, l) }) .take(3) .collect::>(); colours.push("none".to_string()); // add up to 100 for % let weights = [ 5, 5, 65, 25, // the transparent colour ]; let colour_dist = WeightedIndex::new(&weights)?; write!(&mut svg, "")?; for i in 0..50 { let x = (i % 5) * 50; let y = (i / 5) * 50; let colour = &colours[colour_dist.sample(&mut rng)]; write!(&mut svg, "", colour, x, y)?; write!(&mut svg, "", colour, 450 - x, y)?; } write!(&mut svg, "")?; let dest = format!("/var/lib/mnml/public/imgs/{}.svg", id); println!("molecule dest={:?}", dest); let mut file = File::create(dest)?; file.write_all(&svg)?; Ok(id) } enum ConstructShape { Square, Triangle, Circle, Line, V, Tri, Plus, Blank, } // default ? shape pub fn construct(id: Uuid) -> Result { let mut rng = thread_rng(); let mut svg = Vec::new(); // distribution for lightness // bellcurve around 75% let l_dist = Normal::new(50.0, 10.0); let s_dist = Normal::new(25.0, 10.0); // 8 6 or 4 points in shape // 1 head point // n / 2 shapes with a colour each // random size/radius props for each // add up to 100 for % let shapes = [ (ConstructShape::Square, 100), // (ConstructShape::Triangle, 10), // (ConstructShape::Circle, 10), // (ConstructShape::Line, 10), // (ConstructShape::V, 10), // (ConstructShape::Tri, 3), // (ConstructShape::Plus, 5), // (ConstructShape::Blank, 1), ]; let shape_dist = WeightedIndex::new(shapes.iter().map(|v| v.1))?; let n_shapes = rng.gen_range(2, 10); write!(&mut svg, "")?; for i in 0..n_shapes - 1 { let h = rng.gen_range(0, 360); let s = s_dist.sample(&mut rng) as usize; let l = l_dist.sample(&mut rng) as usize; let colour = format!("hsl({:}, {:}%, {:}%)", h, s, l); let fraction: f64 = (1.0 / n_shapes as f64) * i as f64; let angle: f64 = (fraction * 180.0) / f64::consts::PI; match shapes[shape_dist.sample(&mut rng)].0 { ConstructShape::Square => { let size = rng.gen_range(5, 50); let distance = rng.gen_range(50, 200); let rotation = rng.gen_range(0, 180); write!(&mut svg, "", colour, size / 2, size / 2, size, size, rotation, distance, angle)?; write!(&mut svg, "", colour, size / 2, size / 2, size, size, rotation, distance, angle + 180.0)?; }, ConstructShape::Triangle => { }, ConstructShape::Circle => { }, ConstructShape::Line => { }, ConstructShape::V => { }, ConstructShape::Tri => { }, ConstructShape::Plus => { }, ConstructShape::Blank => { }, } } write!(&mut svg, "")?; let dest = format!("/var/lib/mnml/public/imgs/{}.svg", id); println!("default dest={:?}", dest); let mut file = File::create(dest)?; file.write_all(&svg)?; Ok(id) } fn _hieroglyph() -> String { let mut rng = thread_rng(); let mut s = String::new(); for i in 0..4 { s.push(from_u32(rng.gen_range(0x13000, 0x1342E)).unwrap()); if i == 1 { // newline s.push(from_u32(0x000a).unwrap()); } } // println!("{:}", s); return s; } #[cfg(test)] mod tests { use super::*; // #[test] // fn invader_img_test() { // for i in 0..100 { // invader_img_write(Uuid::new_v4()).unwrap(); // } // } // #[test] // fn hieroglyph_test() { // hieroglyph(); // } #[test] fn construct_img_test() { for i in 0..100 { construct(Uuid::new_v4()).unwrap(); } } } // function createColor() { // //saturation is the whole color spectrum // var h = Math.floor(rand() * 360); // //saturation goes from 40 to 100, it avoids greyish colors // var s = ((rand() * 60) + 40) + '%'; // //lightness can be anything from 0 to 100, but probabilities are a bell curve around 75% // var l = ((rand()+rand()+rand()+rand()) * 25) + '%'; // var color = 'hsl(' + h + ',' + s + ',' + l + ')'; // return color; // } // function createImageData(size) { // var width = size; // Only support square icons for now // var height = size; // var dataWidth = Math.ceil(width / 2); // var mirrorWidth = width - dataWidth; // var data = []; // for(var y = 0; y < height; y++) { // var row = []; // for(var x = 0; x < dataWidth; x++) { // // this makes foreground and background color to have a 43% (1/2.3) probability // // spot color has 13% chance // row[x] = Math.floor(rand()*2.3); // } // var r = row.slice(0, mirrorWidth); // r.reverse(); // row = row.concat(r); // for(var i = 0; i < row.length; i++) { // data.push(row[i]); // } // } // return data; // } // function buildOpts(opts) { // var newOpts = {}; // newOpts.seed = opts.seed || Math.floor((Math.random()*Math.pow(10,16))).toString(16); // seedrand(newOpts.seed); // newOpts.size = opts.size || 8; // newOpts.scale = opts.scale || 4; // newOpts.color = opts.color || createColor(); // newOpts.bgcolor = opts.bgcolor || createColor(); // newOpts.spotcolor = opts.spotcolor || createColor(); // return newOpts; // } // ], // - _ => vec![ // - (ItemAction::RerollStamina, 1), // - (ItemAction::RerollPhysDamage, 1), // - (ItemAction::RerollSpellDamage, 1), // - (ItemAction::RerollSpeed, 1), // - (ItemAction::RerollArmour, 1), // - (ItemAction::RerollSpellShield, 1), // - (ItemAction::RerollEvasion, 1), // - ], // + // _ => vec![ // + // (ItemAction::RerollStamina, 1), // + // (ItemAction::RerollPhysDamage, 1), // + // (ItemAction::RerollSpellDamage, 1), // + // (ItemAction::RerollSpeed, 1), // + // (ItemAction::RerollArmour, 1), // + // (ItemAction::RerollSpellShield, 1), // + // (ItemAction::RerollEvasion, 1), // + // ], // } // } // -pub fn item_drop(tx: &mut Transaction, account_id: Uuid, mode: GameMode) -> Result { // +pub fn item_drop(tx: &mut Transaction, account_id: Uuid, mode: GameMode) -> Result<(), Error> { // let mut rng = thread_rng(); // - let actions = mode_drops(mode); // + let log_normal = LogNormal::new(1.0, 1.0); // + let num_drops = log_normal.sample(&mut rng).floor() as usize; // + // + println!("{:?} drops", num_drops); // - let dist = WeightedIndex::new(actions.iter().map(|item| item.1)).unwrap(); // - let kind = actions[dist.sample(&mut rng)].0; // - let item = Item::new(kind, account_id); // + for _i in 0..num_drops { // + let actions = mode_drops(mode); // - println!("{:?} dropped {:?}", account_id, item); // + let dist = WeightedIndex::new(actions.iter().map(|item| item.1)).unwrap(); // + let kind = actions[dist.sample(&mut rng)].0; // + let item = Item::new(kind, account_id); // - return item_create(item, tx, account_id); // + println!("{:?} dropped {:?}", account_id, item); // + item_create(item, tx, account_id)?;V