Refactor into different crates

This commit is contained in:
hal8174 2025-01-18 17:30:55 +01:00
parent 94473c64e0
commit dfdeae5638
82 changed files with 624 additions and 647 deletions

View file

@ -0,0 +1,432 @@
use super::Visualization;
use crate::{prelude::Direction, visualize::Symbol};
use image::{GenericImage, Rgba, RgbaImage};
pub(super) fn draw<I: GenericImage<Pixel = Rgba<u8>>>(v: &Visualization, image: &mut I) {
assert_eq!(
(v.size.x as u32 * 10, v.size.y as u32 * 10),
image.dimensions()
);
for (pos, (symbol, fg, bg)) in &v.symbols {
match symbol {
Symbol::Arrow(dir) => {
if let Some(c) = bg.as_ref() {
let rgba = Rgba::from([c.r, c.g, c.b, 255]);
for x in 0..10 {
for y in 0..10 {
image.put_pixel((pos.x * 10 + x) as u32, (pos.y * 10 + y) as u32, rgba);
}
}
}
if let Some(c) = fg.as_ref() {
let rgba = Rgba::from([c.r, c.g, c.b, 255]);
for p in rotate_iter(*dir, arrow()) {
image.put_pixel((pos.x * 10) as u32 + p.0, (pos.y * 10) as u32 + p.1, rgba);
}
}
}
Symbol::ArrowEnter(dir) => {
if let Some(c) = bg.as_ref() {
let rgba = Rgba::from([c.r, c.g, c.b, 255]);
for x in 0..10 {
for y in 0..10 {
image.put_pixel((pos.x * 10 + x) as u32, (pos.y * 10 + y) as u32, rgba);
}
}
}
if let Some(c) = fg.as_ref() {
let rgba = Rgba::from([c.r, c.g, c.b, 255]);
for p in rotate_iter(*dir, arrow_enter()) {
image.put_pixel((pos.x * 10) as u32 + p.0, (pos.y * 10) as u32 + p.1, rgba);
}
}
}
Symbol::ArrowExit(dir) => {
if let Some(c) = bg.as_ref() {
let rgba = Rgba::from([c.r, c.g, c.b, 255]);
for x in 0..10 {
for y in 0..10 {
image.put_pixel((pos.x * 10 + x) as u32, (pos.y * 10 + y) as u32, rgba);
}
}
}
if let Some(c) = fg.as_ref() {
let rgba = Rgba::from([c.r, c.g, c.b, 255]);
for p in rotate_iter(*dir, arrow_exit()) {
image.put_pixel((pos.x * 10) as u32 + p.0, (pos.y * 10) as u32 + p.1, rgba);
}
}
}
Symbol::Char(ch) => {
if let Some(c) = bg.as_ref() {
let rgba = Rgba::from([c.r, c.g, c.b, 255]);
for x in 0..10 {
for y in 0..10 {
image.put_pixel((pos.x * 10 + x) as u32, (pos.y * 10 + y) as u32, rgba);
}
}
}
if let Some(c) = fg.as_ref() {
let rgba = Rgba::from([c.r, c.g, c.b, 255]);
for p in char(*ch) {
image.put_pixel((pos.x * 10) as u32 + p.0, (pos.y * 10) as u32 + p.1, rgba);
}
}
}
Symbol::Block => {
if let Some(c) = fg.as_ref() {
let rgba = Rgba::from([c.r, c.g, c.b, 255]);
for x in 1..9 {
for y in 1..9 {
image.put_pixel((pos.x * 10 + x) as u32, (pos.y * 10 + y) as u32, rgba);
}
}
}
if let Some(c) = bg.as_ref() {
let rgba = Rgba::from([c.r, c.g, c.b, 255]);
for x in 0..10 {
image.put_pixel((pos.x * 10 + x) as u32, (pos.y * 10) as u32, rgba);
image.put_pixel((pos.x * 10 + x) as u32, (pos.y * 10 + 9) as u32, rgba);
}
for y in 1..9 {
image.put_pixel((pos.x * 10) as u32, (pos.y * 10 + y) as u32, rgba);
image.put_pixel((pos.x * 10 + 9) as u32, (pos.y * 10 + y) as u32, rgba);
}
}
}
Symbol::Space => {
if let Some(c) = bg.as_ref() {
let rgba = Rgba::from([c.r, c.g, c.b, 255]);
for x in 0..10 {
for y in 0..10 {
image.put_pixel((pos.x * 10 + x) as u32, (pos.y * 10 + y) as u32, rgba);
}
}
}
}
}
}
}
pub fn image_grid(
visualizations: &[Visualization],
width: u32,
height: u32,
columns: u32,
) -> RgbaImage {
let border_color = Rgba::from([255, 255, 255, 255]);
let rows = visualizations.len().div_ceil(columns as usize) as u32;
let mut img = RgbaImage::new((width * 10 + 2) * columns, (height * 10 + 2) * rows);
for (i, v) in visualizations.iter().enumerate() {
let i = i as u32;
let r = i / columns;
let c = i % columns;
let size = v.size();
let mut sub_img = img.sub_image(
1 + c * (width * 10 + 2),
1 + r * (height * 10 + 2),
(size.x as u32) * 10,
(size.y as u32) * 10,
);
draw(v, &mut *sub_img);
for x in 0..(size.x as u32 * 10 + 2) {
img.put_pixel(
c * (width * 10 + 2) + x,
r * (height * 10 + 2),
border_color,
);
img.put_pixel(
c * (width * 10 + 2) + x,
r * (height * 10 + 2) + (size.y as u32) * 10 + 1,
border_color,
);
}
for y in 0..(size.y as u32 * 10 + 2) {
img.put_pixel(
c * (width * 10 + 2),
r * (height * 10 + 2) + y,
border_color,
);
img.put_pixel(
c * (width * 10 + 2) + (size.x as u32) * 10 + 1,
r * (height * 10 + 2) + y,
border_color,
);
}
}
img
}
fn rotate(dir: Direction, pos: (u32, u32)) -> (u32, u32) {
match dir {
Direction::Up => pos,
Direction::Right => (9 - pos.1, pos.0),
Direction::Down => (9 - pos.0, 9 - pos.1),
Direction::Left => (pos.1, 9 - pos.0),
}
}
fn rotate_iter(
dir: Direction,
iter: impl Iterator<Item = (u32, u32)>,
) -> impl Iterator<Item = (u32, u32)> {
iter.map(move |p| rotate(dir, p))
}
fn arrow() -> impl Iterator<Item = (u32, u32)> {
[
(4, 1),
(5, 1),
(3, 2),
(4, 2),
(5, 2),
(6, 2),
(2, 3),
(3, 3),
(4, 3),
(5, 3),
(6, 3),
(7, 3),
(1, 4),
(2, 4),
(4, 4),
(5, 4),
(7, 4),
(8, 4),
(4, 5),
(5, 5),
(4, 6),
(5, 6),
(4, 7),
(5, 7),
(4, 8),
(5, 8),
]
.into_iter()
}
fn arrow_enter() -> impl Iterator<Item = (u32, u32)> {
[
(2, 1),
(3, 1),
(4, 1),
(5, 1),
(6, 1),
(7, 1),
(3, 2),
(4, 2),
(5, 2),
(6, 2),
(2, 3),
(3, 3),
(4, 3),
(5, 3),
(6, 3),
(7, 3),
(1, 4),
(2, 4),
(4, 4),
(5, 4),
(7, 4),
(8, 4),
(4, 5),
(5, 5),
(4, 6),
(5, 6),
(4, 7),
(5, 7),
(4, 8),
(5, 8),
]
.into_iter()
}
fn arrow_exit() -> impl Iterator<Item = (u32, u32)> {
[
(4, 1),
(5, 1),
(3, 2),
(4, 2),
(5, 2),
(6, 2),
(2, 3),
(3, 3),
(4, 3),
(5, 3),
(6, 3),
(7, 3),
(1, 4),
(2, 4),
(4, 4),
(5, 4),
(7, 4),
(8, 4),
(4, 5),
(5, 5),
(4, 6),
(5, 6),
(2, 7),
(3, 7),
(4, 7),
(5, 7),
(6, 7),
(7, 7),
]
.into_iter()
}
static CHARDATA: [[u8; 8]; 128] = [
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], // U+0000 (nul)
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], // U+0001
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], // U+0002
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], // U+0003
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], // U+0004
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], // U+0005
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], // U+0006
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], // U+0007
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], // U+0008
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], // U+0009
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], // U+000A
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], // U+000B
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], // U+000C
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], // U+000D
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], // U+000E
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], // U+000F
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], // U+0010
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], // U+0011
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], // U+0012
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], // U+0013
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], // U+0014
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], // U+0015
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], // U+0016
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], // U+0017
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], // U+0018
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], // U+0019
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], // U+001A
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], // U+001B
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], // U+001C
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], // U+001D
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], // U+001E
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], // U+001F
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], // U+0020 (space)
[0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00], // U+0021 (!)
[0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], // U+0022 (")
[0x36, 0x36, 0x7F, 0x36, 0x7F, 0x36, 0x36, 0x00], // U+0023 (#)
[0x0C, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x0C, 0x00], // U+0024 ($)
[0x00, 0x63, 0x33, 0x18, 0x0C, 0x66, 0x63, 0x00], // U+0025 (%)
[0x1C, 0x36, 0x1C, 0x6E, 0x3B, 0x33, 0x6E, 0x00], // U+0026 (&)
[0x06, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00], // U+0027 (')
[0x18, 0x0C, 0x06, 0x06, 0x06, 0x0C, 0x18, 0x00], // U+0028 (()
[0x06, 0x0C, 0x18, 0x18, 0x18, 0x0C, 0x06, 0x00], // U+0029 ())
[0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00], // U+002A (*)
[0x00, 0x0C, 0x0C, 0x3F, 0x0C, 0x0C, 0x00, 0x00], // U+002B (+)
[0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x06], // U+002C (,)
[0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00], // U+002D (-)
[0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00], // U+002E (.)
[0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00], // U+002F (/)
[0x3E, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x3E, 0x00], // U+0030 (0)
[0x0C, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x00], // U+0031 (1)
[0x1E, 0x33, 0x30, 0x1C, 0x06, 0x33, 0x3F, 0x00], // U+0032 (2)
[0x1E, 0x33, 0x30, 0x1C, 0x30, 0x33, 0x1E, 0x00], // U+0033 (3)
[0x38, 0x3C, 0x36, 0x33, 0x7F, 0x30, 0x78, 0x00], // U+0034 (4)
[0x3F, 0x03, 0x1F, 0x30, 0x30, 0x33, 0x1E, 0x00], // U+0035 (5)
[0x1C, 0x06, 0x03, 0x1F, 0x33, 0x33, 0x1E, 0x00], // U+0036 (6)
[0x3F, 0x33, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x00], // U+0037 (7)
[0x1E, 0x33, 0x33, 0x1E, 0x33, 0x33, 0x1E, 0x00], // U+0038 (8)
[0x1E, 0x33, 0x33, 0x3E, 0x30, 0x18, 0x0E, 0x00], // U+0039 (9)
[0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x00], // U+003A (:)
[0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x06], // U+003B (;)
[0x18, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x18, 0x00], // U+003C (<)
[0x00, 0x00, 0x3F, 0x00, 0x00, 0x3F, 0x00, 0x00], // U+003D (=)
[0x06, 0x0C, 0x18, 0x30, 0x18, 0x0C, 0x06, 0x00], // U+003E (>)
[0x1E, 0x33, 0x30, 0x18, 0x0C, 0x00, 0x0C, 0x00], // U+003F (?)
[0x3E, 0x63, 0x7B, 0x7B, 0x7B, 0x03, 0x1E, 0x00], // U+0040 (@)
[0x0C, 0x1E, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x00], // U+0041 (A)
[0x3F, 0x66, 0x66, 0x3E, 0x66, 0x66, 0x3F, 0x00], // U+0042 (B)
[0x3C, 0x66, 0x03, 0x03, 0x03, 0x66, 0x3C, 0x00], // U+0043 (C)
[0x1F, 0x36, 0x66, 0x66, 0x66, 0x36, 0x1F, 0x00], // U+0044 (D)
[0x7F, 0x46, 0x16, 0x1E, 0x16, 0x46, 0x7F, 0x00], // U+0045 (E)
[0x7F, 0x46, 0x16, 0x1E, 0x16, 0x06, 0x0F, 0x00], // U+0046 (F)
[0x3C, 0x66, 0x03, 0x03, 0x73, 0x66, 0x7C, 0x00], // U+0047 (G)
[0x33, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x33, 0x00], // U+0048 (H)
[0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00], // U+0049 (I)
[0x78, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E, 0x00], // U+004A (J)
[0x67, 0x66, 0x36, 0x1E, 0x36, 0x66, 0x67, 0x00], // U+004B (K)
[0x0F, 0x06, 0x06, 0x06, 0x46, 0x66, 0x7F, 0x00], // U+004C (L)
[0x63, 0x77, 0x7F, 0x7F, 0x6B, 0x63, 0x63, 0x00], // U+004D (M)
[0x63, 0x67, 0x6F, 0x7B, 0x73, 0x63, 0x63, 0x00], // U+004E (N)
[0x1C, 0x36, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00], // U+004F (O)
[0x3F, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x0F, 0x00], // U+0050 (P)
[0x1E, 0x33, 0x33, 0x33, 0x3B, 0x1E, 0x38, 0x00], // U+0051 (Q)
[0x3F, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x67, 0x00], // U+0052 (R)
[0x1E, 0x33, 0x07, 0x0E, 0x38, 0x33, 0x1E, 0x00], // U+0053 (S)
[0x3F, 0x2D, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00], // U+0054 (T)
[0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0x00], // U+0055 (U)
[0x33, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00], // U+0056 (V)
[0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00], // U+0057 (W)
[0x63, 0x63, 0x36, 0x1C, 0x1C, 0x36, 0x63, 0x00], // U+0058 (X)
[0x33, 0x33, 0x33, 0x1E, 0x0C, 0x0C, 0x1E, 0x00], // U+0059 (Y)
[0x7F, 0x63, 0x31, 0x18, 0x4C, 0x66, 0x7F, 0x00], // U+005A (Z)
[0x1E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x1E, 0x00], // U+005B ([)
[0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00], // U+005C (\)
[0x1E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1E, 0x00], // U+005D (])
[0x08, 0x1C, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00], // U+005E (^)
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF], // U+005F (_)
[0x0C, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00], // U+0060 (`)
[0x00, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x6E, 0x00], // U+0061 (a)
[0x07, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3B, 0x00], // U+0062 (b)
[0x00, 0x00, 0x1E, 0x33, 0x03, 0x33, 0x1E, 0x00], // U+0063 (c)
[0x38, 0x30, 0x30, 0x3e, 0x33, 0x33, 0x6E, 0x00], // U+0064 (d)
[0x00, 0x00, 0x1E, 0x33, 0x3f, 0x03, 0x1E, 0x00], // U+0065 (e)
[0x1C, 0x36, 0x06, 0x0f, 0x06, 0x06, 0x0F, 0x00], // U+0066 (f)
[0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x1F], // U+0067 (g)
[0x07, 0x06, 0x36, 0x6E, 0x66, 0x66, 0x67, 0x00], // U+0068 (h)
[0x0C, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00], // U+0069 (i)
[0x30, 0x00, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E], // U+006A (j)
[0x07, 0x06, 0x66, 0x36, 0x1E, 0x36, 0x67, 0x00], // U+006B (k)
[0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00], // U+006C (l)
[0x00, 0x00, 0x33, 0x7F, 0x7F, 0x6B, 0x63, 0x00], // U+006D (m)
[0x00, 0x00, 0x1F, 0x33, 0x33, 0x33, 0x33, 0x00], // U+006E (n)
[0x00, 0x00, 0x1E, 0x33, 0x33, 0x33, 0x1E, 0x00], // U+006F (o)
[0x00, 0x00, 0x3B, 0x66, 0x66, 0x3E, 0x06, 0x0F], // U+0070 (p)
[0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x78], // U+0071 (q)
[0x00, 0x00, 0x3B, 0x6E, 0x66, 0x06, 0x0F, 0x00], // U+0072 (r)
[0x00, 0x00, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x00], // U+0073 (s)
[0x08, 0x0C, 0x3E, 0x0C, 0x0C, 0x2C, 0x18, 0x00], // U+0074 (t)
[0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x6E, 0x00], // U+0075 (u)
[0x00, 0x00, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00], // U+0076 (v)
[0x00, 0x00, 0x63, 0x6B, 0x7F, 0x7F, 0x36, 0x00], // U+0077 (w)
[0x00, 0x00, 0x63, 0x36, 0x1C, 0x36, 0x63, 0x00], // U+0078 (x)
[0x00, 0x00, 0x33, 0x33, 0x33, 0x3E, 0x30, 0x1F], // U+0079 (y)
[0x00, 0x00, 0x3F, 0x19, 0x0C, 0x26, 0x3F, 0x00], // U+007A (z)
[0x38, 0x0C, 0x0C, 0x07, 0x0C, 0x0C, 0x38, 0x00], // U+007B ([)
[0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00], // U+007C (|)
[0x07, 0x0C, 0x0C, 0x38, 0x0C, 0x0C, 0x07, 0x00], // U+007D (])
[0x6E, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], // U+007E (~)
[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], // U+007F
];
fn char(c: char) -> impl Iterator<Item = (u32, u32)> {
let id = c as usize;
CHARDATA[id]
.iter()
.enumerate()
.flat_map(|(y, &d)| {
(0..8).filter_map(move |x: u32| {
if (d >> x) & 1 == 1 {
Some((x, y as u32))
} else {
None
}
})
})
.map(|(x, y)| (x + 1, y + 1))
}

View file

@ -0,0 +1,137 @@
mod image;
mod print;
use crate::prelude::*;
use ::image::RgbaImage;
pub use image::image_grid;
use std::collections::HashMap;
pub trait Visualize {
fn visualize(&self) -> Visualization;
fn print_visualization(&self) {
let v = self.visualize();
print::print(v);
}
fn png_visualization(&self, file: impl AsRef<std::path::Path>) {
let v = self.visualize();
let mut img = RgbaImage::new((v.size.x * 10) as u32, (v.size.y * 10) as u32);
image::draw(&v, &mut img);
let mut f = std::fs::File::create(file).unwrap();
let _ = img.write_to(&mut f, ::image::ImageFormat::Png);
}
}
pub enum Symbol {
Arrow(Direction),
ArrowEnter(Direction),
ArrowExit(Direction),
Char(char),
Block,
Space,
}
impl Symbol {
fn get_char(&self) -> char {
match self {
Symbol::Arrow(dir) => match dir {
Direction::Up => '↑',
Direction::Right => '→',
Direction::Down => '↓',
Direction::Left => '←',
},
Symbol::ArrowEnter(dir) => match dir {
Direction::Up => '↟',
Direction::Right => '↠',
Direction::Down => '↡',
Direction::Left => '↞',
},
Symbol::ArrowExit(dir) => match dir {
Direction::Up => '↥',
Direction::Right => '↦',
Direction::Down => '↧',
Direction::Left => '↤',
},
Symbol::Char(c) => *c,
Symbol::Block => '#',
Symbol::Space => ' ',
}
}
}
pub struct Visualization {
size: Position,
symbols: HashMap<Position, (Symbol, Option<Color>, Option<Color>)>,
}
#[derive(Debug, Clone, Copy)]
pub struct Color {
r: u8,
g: u8,
b: u8,
}
impl Color {
pub fn new(r: u8, g: u8, b: u8) -> Self {
Self { r, g, b }
}
pub fn white() -> Self {
Self::new(255, 255, 255)
}
pub fn index(i: usize) -> Self {
let c = [
Color::new(0xe6, 0x00, 0x49),
Color::new(0x0b, 0xb4, 0xff),
Color::new(0x50, 0xe9, 0x91),
Color::new(0xe6, 0xd8, 0x00),
Color::new(0x9b, 0x19, 0xf5),
Color::new(0xff, 0xa3, 0x00),
Color::new(0xdc, 0x0a, 0xb4),
Color::new(0xb3, 0xd4, 0xff),
Color::new(0x00, 0xbf, 0xa0),
];
c[i % c.len()]
}
}
impl Visualization {
pub fn new(size: Position) -> Self {
Self {
size,
symbols: HashMap::new(),
}
}
pub fn add_symbol(
&mut self,
pos: Position,
symbol: Symbol,
fg: Option<Color>,
bg: Option<Color>,
) {
if let Some(s) = self.symbols.get_mut(&pos) {
*s = (symbol, fg, bg);
} else {
self.symbols.insert(pos, (symbol, fg, bg));
}
}
pub fn overwrite_background(&mut self, pos: Position, bg: Option<Color>) {
if let Some(s) = self.symbols.get_mut(&pos) {
s.2 = bg;
} else {
self.symbols.insert(pos, (Symbol::Space, None, bg));
}
}
pub fn size(&self) -> Position {
self.size
}
}

View file

@ -0,0 +1,81 @@
use super::Visualization;
use std::io::Write;
use termcolor::{ColorSpec, StandardStream, WriteColor};
use crate::prelude::*;
pub(super) fn print(v: Visualization) {
let stdout = &mut StandardStream::stdout(termcolor::ColorChoice::Always);
let width_digits = (v.size.x - 1).ilog10() + 1;
let height_digits = (v.size.y - 1).ilog10() + 1;
// print header
for i in 0..width_digits {
let d = width_digits - i - 1;
//padding
for _ in 0..height_digits {
write!(stdout, " ").unwrap();
}
for x in 0..v.size.x {
let digits = x / (i32::pow(10, d));
if digits == 0 && d > 0 {
write!(stdout, " ").unwrap();
} else {
write!(
stdout,
"{}",
char::from_u32((digits % 10) as u32 + 48).unwrap()
)
.unwrap();
}
}
writeln!(stdout).unwrap();
}
for y in 0..v.size.y {
write!(stdout, "{:1$}", y, height_digits as usize).unwrap();
for x in 0..v.size.x {
if let Some((s, fg, bg)) = v.symbols.get(&Position::new(x, y)) {
let mut c = ColorSpec::new();
c.set_fg(fg.as_ref().map(|c| termcolor::Color::Rgb(c.r, c.g, c.b)));
c.set_bg(bg.as_ref().map(|c| termcolor::Color::Rgb(c.r, c.g, c.b)));
stdout.set_color(&c).unwrap();
write!(stdout, "{:1}", s.get_char()).unwrap();
stdout.reset().unwrap();
} else {
write!(stdout, " ").unwrap();
}
}
writeln!(stdout, "{:1$}", y, height_digits as usize).unwrap();
}
for i in 0..width_digits {
let d = width_digits - i - 1;
//padding
for _ in 0..height_digits {
write!(stdout, " ").unwrap();
}
for x in 0..v.size.x {
let digits = x / (i32::pow(10, d));
if digits == 0 && d > 0 {
write!(stdout, " ").unwrap();
} else {
write!(
stdout,
"{}",
char::from_u32((digits % 10) as u32 + 48).unwrap()
)
.unwrap();
}
}
writeln!(stdout).unwrap();
}
}