use std::error::Error; | |
use std::io::{prelude::*, stdin}; | |
type AsciiArtResult<T> = Result<T, Box<Error>>; | |
#[derive(Debug, Default, PartialEq)] | |
struct AsciiArtData { | |
alphabet_rows: Vec<String>, | |
letter_width: u8, | |
letter_height: u8, | |
sentence: String, | |
} | |
impl AsciiArtData { | |
fn from(reader: impl BufRead) -> AsciiArtResult<Self> { | |
let mut input_lines = reader.lines().map(|l| l.unwrap()); | |
let w: u8 = input_lines | |
.next() | |
.expect("Cannot read letter width") | |
.trim() | |
.parse() | |
.expect("Cannot parse letter width"); | |
let h: u8 = input_lines | |
.next() | |
.expect("Cannot read letter height") | |
.trim() | |
.parse() | |
.expect("Cannot parse letter height"); | |
let txt: String = input_lines | |
.next() | |
.expect("Cannot read sentence") | |
.trim_end() | |
.to_uppercase() | |
.parse() | |
.expect("Cannot parse sentence"); | |
let rows: Vec<String> = input_lines | |
.take(h as usize) | |
.map(|x| x.trim_end().to_owned()) | |
.collect::<Vec<String>>(); | |
Ok(Self { | |
letter_width: w, | |
letter_height: h, | |
sentence: txt, | |
alphabet_rows: rows, | |
}) | |
} | |
fn process(self) -> String { | |
let mut text_out = String::new(); | |
for row in self.alphabet_rows { | |
// FIXME: For some reason, first character of first row is already consumed | |
for c in self.sentence.chars() { | |
let letter_width = self.letter_width as usize; | |
let idx_start = if c.is_ascii_uppercase() { | |
(c as usize - 'A' as usize) | |
} else { | |
26 | |
} * letter_width; | |
let substring = unsafe { row.get_unchecked(idx_start..(idx_start + letter_width)) }; | |
text_out.push_str(substring); | |
} | |
text_out.push('\n') | |
} | |
text_out | |
} | |
} | |
// Try with "E", "MANHATTAN", "ManhAtTan", "M@NH@TT@N" | |
#[test] | |
fn letters_4x5_with_only_f() { | |
let input = b"4\n5\nE | |
# ## ## ## ### ### ## # # ### ## # # # # # ### # ## # ## ## ### # # # # # # # # # # ### ### \n\ | |
# # # # # # # # # # # # # # # # # ### # # # # # # # # # # # # # # # # # # # # # # # # \n\ | |
### ## # # # ## ## # # ### # # ## # ### # # # # ## # # ## # # # # # # ### # # # ## \n\ | |
# # # # # # # # # # # # # # # # # # # # # # # # # # ## # # # # # # # # ### # # # # \n\ | |
# # ## ## ## ### # ## # # ### # # # ### # # # # # # # # # ## # ### # # # # # # ### # "; | |
let expected = "### \n\ | |
# \n\ | |
## \n\ | |
# \n\ | |
### \n"; | |
let actual = AsciiArtData::from(&input[..]).unwrap().process(); | |
println!("{}", actual); | |
assert_eq!(expected, actual); | |
} | |
#[test] | |
fn letters_4x5_with_uppercase_manhattan() { | |
let input = b"4\n5\nMANHATTAN | |
# ## ## ## ### ### ## # # ### ## # # # # # ### # ## # ## ## ### # # # # # # # # # # ### ### \n\ | |
# # # # # # # # # # # # # # # # # ### # # # # # # # # # # # # # # # # # # # # # # # # \n\ | |
### ## # # # ## ## # # ### # # ## # ### # # # # ## # # ## # # # # # # ### # # # ## \n\ | |
# # # # # # # # # # # # # # # # # # # # # # # # # # ## # # # # # # # # ### # # # # \n\ | |
# # ## ## ## ### # ## # # ### # # # ### # # # # # # # # # ## # ### # # # # # # ### # "; | |
let expected = "# # # ### # # # ### ### # ### \n\ | |
### # # # # # # # # # # # # # # \n\ | |
### ### # # ### ### # # ### # # \n\ | |
# # # # # # # # # # # # # # # # \n\ | |
# # # # # # # # # # # # # # # # \n"; | |
let actual = AsciiArtData::from(&input[..]).unwrap().process(); | |
println!("{}", actual); | |
assert_eq!(expected, actual); | |
} | |
fn main() { | |
let stdin = stdin(); | |
match AsciiArtData::from(stdin.lock()) { | |
Ok(data) => println!("{}", data.process()), | |
Err(err) => { | |
eprintln!("Input error: {}", err); | |
std::process::exit(1); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment