use std::fmt::Display;
use crate::GridWriter;
pub trait Sprite {
type Element: Clone;
#[must_use]
fn width(&self) -> usize;
#[must_use]
fn height(&self) -> usize;
fn draw_to(&self, position: (usize, usize), to: &mut impl GridWriter<Element = Self::Element>);
}
pub struct Line<T: Display> {
length: usize,
render: T,
orientation: Orientation,
}
enum Orientation {
Horizontal,
Vertical,
}
impl<T: Display> Line<T> {
#[must_use]
pub fn horizontal(length: usize, render: T) -> Self {
Self {
length,
render,
orientation: Orientation::Horizontal,
}
}
#[must_use]
pub fn vertical(length: usize, render: T) -> Self {
Self {
length,
render,
orientation: Orientation::Vertical,
}
}
}
impl<T: Display + Clone> Sprite for Line<T> {
type Element = T;
fn width(&self) -> usize {
match self.orientation {
Orientation::Horizontal => self.length,
Orientation::Vertical => 1,
}
}
fn height(&self) -> usize {
match self.orientation {
Orientation::Horizontal => 1,
Orientation::Vertical => self.length,
}
}
fn draw_to(&self, position: (usize, usize), to: &mut impl GridWriter<Element = Self::Element>) {
let (x, y) = position;
match self.orientation {
Orientation::Horizontal => {
for i in 0..self.length {
to.set((x + i, y), self.render.clone());
}
}
Orientation::Vertical => {
for i in 0..self.length {
to.set((x, y + i), self.render.clone());
}
}
}
}
}
pub struct FillRect<T: Display> {
width: usize,
height: usize,
render: T,
}
impl<T: Display> FillRect<T> {
#[must_use]
pub fn new(width: usize, height: usize, render: T) -> Self {
Self {
width,
height,
render,
}
}
}
impl<T: Display + Clone> Sprite for FillRect<T> {
type Element = T;
fn width(&self) -> usize {
self.width
}
fn height(&self) -> usize {
self.height
}
fn draw_to(&self, position: (usize, usize), to: &mut impl GridWriter<Element = Self::Element>) {
let (x, y) = position;
for i in 0..self.width {
for j in 0..self.height {
to.set((x + i, y + j), self.render.clone());
}
}
}
}
pub struct BorderRect<T: Display> {
width: usize,
height: usize,
render: [T; 8],
}
impl<T: Display> BorderRect<T> {
#[must_use]
pub fn new(width: usize, height: usize, render: [T; 8]) -> Self {
assert!(width >= 2, "Width must be at least 2");
assert!(height >= 2, "Height must be at least 2");
Self {
width,
height,
render,
}
}
}
impl<T: Display + Clone> BorderRect<T> {
fn top_left(&self) -> T {
self.render[0].clone()
}
fn top(&self) -> T {
self.render[1].clone()
}
fn top_right(&self) -> T {
self.render[2].clone()
}
fn left(&self) -> T {
self.render[3].clone()
}
fn right(&self) -> T {
self.render[4].clone()
}
fn bottom_left(&self) -> T {
self.render[5].clone()
}
fn bottom(&self) -> T {
self.render[6].clone()
}
fn bottom_right(&self) -> T {
self.render[7].clone()
}
}
impl<T: Display + Clone> Sprite for BorderRect<T> {
type Element = T;
fn width(&self) -> usize {
self.width
}
fn height(&self) -> usize {
self.height
}
fn draw_to(&self, position: (usize, usize), to: &mut impl GridWriter<Element = Self::Element>) {
let (x, y) = position;
let width = self.width();
let height = self.height();
for i in 1..width - 1 {
to.set((x + i, y), self.top());
to.set((x + i, y + height - 1), self.bottom());
}
for i in 1..height - 1 {
to.set((x, y + i), self.left());
to.set((x + width - 1, y + i), self.right());
}
to.set((x, y), self.top_left());
to.set((x + width - 1, y), self.top_right());
to.set((x, y + height - 1), self.bottom_left());
to.set((x + width - 1, y + height - 1), self.bottom_right());
}
}