use std::default::Default; use rusttype::{Scale, FontCollection, Font}; use imageproc::drawing; use image::{GrayImage, RgbImage, Rgb, Luma}; use std::path::Path; use imageproc::rect::Rect; use std::fmt; use std::fmt::Display; #[derive(Debug,Clone,Copy,Eq,PartialEq)] pub enum PlayerSide { Black = 0, White = 1, } #[derive(Debug,Clone,Copy)] pub enum Phase { PickSides, Turn(PlayerSide), } #[derive(Debug,Clone,Default)] pub struct Player { pub born_off: u32, pub on_bar: u32, } #[derive(Debug,Clone,Copy)] pub enum Bin { Free, Black(u32), White(u32), } #[derive(Debug)] pub struct Game { pub phase : Phase, pub multiplier : u32, pub roll : [u8; 2], pub players : [Player; 2], pub bins : [Bin; 24], } impl Default for Game { fn default() -> Self { Game { phase: Phase::PickSides, multiplier: 1, roll: [0; 2], players: [ Player::default(), Player::default(), ], bins: [Bin::Free; 24], } } } impl Display for Game { fn fmt(&self, f : &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, " ")?; for n in (13..=24).rev() { write!(f, "{:2}. ", n)?; } write!(f, "\n╭ ")?; for b in &self.bins[12..=23] { match *b { Bin::Free => write!(f, "┈┈┈ ")?, Bin::Black(n) => write!(f, "{:2}█ ", n)?, Bin::White(n) => write!(f, "{:2}░ ", n)? } } write!(f, "╴\n╰ ")?; for b in (&self.bins[0..=11]).iter().rev() { match *b { Bin::Free => write!(f, "┈┈┈ ")?, Bin::Black(n) => write!(f, "{:2}█ ", n)?, Bin::White(n) => write!(f, "{:2}░ ", n)? } } write!(f, "╴\n ")?; for n in (1..=12).rev() { write!(f, "{:2}. ", n)?; } write!(f, "\n")?; Ok(()) } } fn main() { let mut board = Game::default(); board.bins[4] = Bin::Black(5); board.bins[5] = Bin::Black(2); board.bins[6] = Bin::Black(7); board.bins[14] = Bin::White(9); board.bins[15] = Bin::White(10); board.bins[16] = Bin::White(11); board.bins[2] = Bin::White(2); // // let mut image = RgbImage::new(200, 200); // let mut image : RgbImage = RgbImage::new(200, 200); // // let font = Vec::from(include_bytes!("DejaVuSans.ttf") as &[u8]); // let font = FontCollection::from_bytes(font) // .unwrap() // .into_font() // .unwrap(); // // let height = 12.0; // let scale = Scale { // x: height, // y: height, // }; // // let white = Rgb([255u8, 255u8, 255u8]); // // draw_text_mut( // &mut image, // white, // 0, // 0, // scale, // &font, // "Hello, world!", // ); // // imageproc::drawing::draw_line_segment_mut(&mut image, (0.0, 0.0), (200.0,200.0), white); // // let _ = image.save("out.gif").unwrap(); let mut image = CrispImage::new(250, 60); image.fill(BG); fn draw_disc(image : &mut CrispImage, pos: (i32, i32), bin : Bin) { match bin { Bin::Free => { image.circle_filled(GRAY, pos, 7); }, Bin::Black(n) => { let s = n.to_string(); // image.circle_filled(BLACK, pos, 7); image.circle(WHITE, pos, 7); image.text(WHITE, (pos.0 - (s.len() as i32 * 5)/2, pos.1 - 3), &s); }, Bin::White(n) => { let s = n.to_string(); image.circle_filled(WHITE, pos, 7); image.circle(WHITE, pos, 7); image.text(BLACK, (pos.0 - (s.len() as i32 * 5)/2, pos.1 - 3), &s); }, } } for (i, n) in (13..=24).enumerate() { let s = n.to_string(); image.text(YELLOW, (10 + 20 * i as i32 - (s.len() as i32 * 5)/2, 2), &s); } for (i, n) in (1..=12).rev().enumerate() { let s = n.to_string(); image.text(YELLOW, (10 + 20 * i as i32 - (s.len() as i32 * 5)/2, 51), &s); } // // let s = "1"; // image.text(YELLOW, (10 - (s.len() as i32 * 5)/2, 2), &s); // // let s = "13"; // image.text(YELLOW, (30 - (s.len() as i32 * 5)/2, 2), &s); draw_disc(&mut image, (10, 20), Bin::Black(7)); draw_disc(&mut image, (30, 20), Bin::Black(13)); draw_disc(&mut image, (50, 20), Bin::Free); draw_disc(&mut image, (70, 20), Bin::White(69)); draw_disc(&mut image, (90, 20), Bin::White(9)); for n in 1..=7 { draw_disc(&mut image, (90+n*20, 20), Bin::Free); } for n in 0..=11 { draw_disc(&mut image, (10 + n*20, 40), Bin::Free); } image.render("out.png"); println!("{}", board); } type Color = Rgb; struct CrispImage<'a> { image : RgbImage, font: Font<'a>, width: u32, height: u32, font_scale: Scale, } const BG : Color = Rgb([18, 26, 36]); const BLACK : Color = Rgb([0, 0, 0]); const GRAY : Color = Rgb([67, 83, 104]); const WHITE : Color = Rgb([255, 255, 255]); const RED : Color = Rgb([255, 0, 0]); const YELLOW : Color = Rgb([255, 255, 0]); const GREEN : Color = Rgb([0, 255, 0]); const BLUE : Color = Rgb([0, 0, 255]); const CYAN : Color = Rgb([0, 255, 255]); const MAGENTA : Color = Rgb([255, 0, 255]); impl<'a> CrispImage<'a> { fn new(width: u32, height: u32) -> Self { let mut image : RgbImage = RgbImage::new(width, height); // let font_bytes = include_bytes!("DejaVuSans.ttf"); // let font_bytes = include_bytes!("lilliput steps.ttf"); // let font_bytes = include_bytes!("fixedsys.ttf"); // 16.2 // let font_bytes = include_bytes!("DOSVGA.ttf"); // 16 let font_bytes = include_bytes!("coders_crux.ttf"); // 8.86 let font = Vec::from(font_bytes as &[u8]); let font = FontCollection::from_bytes(font) .unwrap() .into_font() .unwrap(); Self { image, font, width, height, font_scale: Scale { /* x: 16., y: 16.,*/ x: 8.86, y: 8.86, }, } } fn fill(&mut self, color: Color) { self.rect_filled(color, (0,0), (self.width, self.height)); } fn render(&self, path : impl AsRef) { let _ = self.image.save(path).unwrap(); } fn font_scale(&mut self, f : f32) { self.font_scale.x = f; self.font_scale.y = f; } fn text(&mut self, color: Color, pos : (i32, i32), text: &str) { assert!(pos.0 >= 0); assert!(pos.1 >= 0); drawing::draw_text_mut( &mut self.image, color, pos.0 as u32, pos.1 as u32, self.font_scale, &self.font, text, ); } fn circle(&mut self, color: Color, center: (i32, i32), radius: i32) { drawing::draw_hollow_circle_mut(&mut self.image, center, radius, color); } fn circle_filled(&mut self, color: Color, center: (i32, i32), radius: i32) { drawing::draw_filled_circle_mut(&mut self.image, center, radius, color); } fn line(&mut self, color: Color, from: (i32, i32), to: (i32, i32)) { drawing::draw_line_segment_mut(&mut self.image, (from.0 as f32, from.1 as f32), (to.0 as f32, to.1 as f32), color); } fn rect(&mut self, color: Color, tl: (i32, i32), size: (u32, u32)) { drawing::draw_hollow_rect_mut(&mut self.image, Rect::at(tl.0, tl.1).of_size(size.0, size.1), color); } fn rect_filled(&mut self, color: Color, tl: (i32, i32), size: (u32, u32)) { drawing::draw_filled_rect_mut(&mut self.image, Rect::at(tl.0, tl.1).of_size(size.0, size.1), color); } }