1extern crate itertools;
2extern crate unicode_segmentation;
3
4use std::io::BufReader;
5use std::{io};
6
7use itertools::Itertools;
8use std::io::BufRead;
9use unicode_segmentation::UnicodeSegmentation;
10
11const LOOKUP_TABLE : [char; 256] =
12[
13 '⠀', '⠁', '⠂', '⠃', '⠄', '⠅', '⠆', '⠇', '⡀', '⡁', '⡂', '⡃', '⡄', '⡅', '⡆', '⡇',
14'⠈', '⠉', '⠊', '⠋', '⠌', '⠍', '⠎', '⠏', '⡈', '⡉', '⡊', '⡋', '⡌', '⡍', '⡎', '⡏',
15'⠐', '⠑', '⠒', '⠓', '⠔', '⠕', '⠖', '⠗', '⡐', '⡑', '⡒', '⡓', '⡔', '⡕', '⡖', '⡗',
16'⠘', '⠙', '⠚', '⠛', '⠜', '⠝', '⠞', '⠟', '⡘', '⡙', '⡚', '⡛', '⡜', '⡝', '⡞', '⡟',
17'⠠', '⠡', '⠢', '⠣', '⠤', '⠥', '⠦', '⠧', '⡠', '⡡', '⡢', '⡣', '⡤', '⡥', '⡦', '⡧',
18'⠨', '⠩', '⠪', '⠫', '⠬', '⠭', '⠮', '⠯', '⡨', '⡩', '⡪', '⡫', '⡬', '⡭', '⡮', '⡯',
19'⠰', '⠱', '⠲', '⠳', '⠴', '⠵', '⠶', '⠷', '⡰', '⡱', '⡲', '⡳', '⡴', '⡵', '⡶', '⡷',
20'⠸', '⠹', '⠺', '⠻', '⠼', '⠽', '⠾', '⠿', '⡸', '⡹', '⡺', '⡻', '⡼', '⡽', '⡾', '⡿',
21'⢀', '⢁', '⢂', '⢃', '⢄', '⢅', '⢆', '⢇', '⣀', '⣁', '⣂', '⣃', '⣄', '⣅', '⣆', '⣇',
22'⢈', '⢉', '⢊', '⢋', '⢌', '⢍', '⢎', '⢏', '⣈', '⣉', '⣊', '⣋', '⣌', '⣍', '⣎', '⣏',
23'⢐', '⢑', '⢒', '⢓', '⢔', '⢕', '⢖', '⢗', '⣐', '⣑', '⣒', '⣓', '⣔', '⣕', '⣖', '⣗',
24'⢘', '⢙', '⢚', '⢛', '⢜', '⢝', '⢞', '⢟', '⣘', '⣙', '⣚', '⣛', '⣜', '⣝', '⣞', '⣟',
25'⢠', '⢡', '⢢', '⢣', '⢤', '⢥', '⢦', '⢧', '⣠', '⣡', '⣢', '⣣', '⣤', '⣥', '⣦', '⣧',
26'⢨', '⢩', '⢪', '⢫', '⢬', '⢭', '⢮', '⢯', '⣨', '⣩', '⣪', '⣫', '⣬', '⣭', '⣮', '⣯',
27'⢰', '⢱', '⢲', '⢳', '⢴', '⢵', '⢶', '⢷', '⣰', '⣱', '⣲', '⣳', '⣴', '⣵', '⣶', '⣷',
28'⢸', '⢹', '⢺', '⢻', '⢼', '⢽', '⢾', '⢿', '⣸', '⣹', '⣺', '⣻', '⣼', '⣽', '⣾', '⣿',
29];
30
31fn byte_to_braillechar(nb : u8) -> char {
51
52 let nb = nb as u32;
53 let mut ub = 0u32;
54 ub |= ((nb >> 0) & 0x7) << 0;
55 ub |= ((nb >> 4) & 0x7) << 3;
56 ub |= ((nb >> 3) & 0x1) << 6;
57 ub |= ((nb >> 7) & 0x1) << 7;
58
59
60
61 std::char::from_u32(0x2800u32 + ub).unwrap()
62}
63
64#[allow(unused)]
65fn generate_lookup_table() {
67 for bin2 in 0..16 {
68 println!(
69 "'{}', '{}', '{}', '{}', '{}', '{}', '{}', '{}', '{}', '{}', '{}', '{}', '{}', '{}', '{}', '{}',",
70 byte_to_braillechar(bin2 * 16 + 0),
71 byte_to_braillechar(bin2 * 16 + 1),
72 byte_to_braillechar(bin2 * 16 + 2),
73 byte_to_braillechar(bin2 * 16 + 3),
74 byte_to_braillechar(bin2 * 16 + 4),
75 byte_to_braillechar(bin2 * 16 + 5),
76 byte_to_braillechar(bin2 * 16 + 6),
77 byte_to_braillechar(bin2 * 16 + 7),
78 byte_to_braillechar(bin2 * 16 + 8),
79 byte_to_braillechar(bin2 * 16 + 9),
80 byte_to_braillechar(bin2 * 16 + 10),
81 byte_to_braillechar(bin2 * 16 + 11),
82 byte_to_braillechar(bin2 * 16 + 12),
83 byte_to_braillechar(bin2 * 16 + 13),
84 byte_to_braillechar(bin2 * 16 + 14),
85 byte_to_braillechar(bin2 * 16 + 15),
86 )
87 }
88}
89
90const BRAILLE_Y :usize = 4;
91#[allow(unused)]
92const BRAILLE_X :usize = 2;
93
94pub fn to_minimap<'a, R>(reader: R, settings: Settings) -> Box<Iterator<Item = String> + 'a>
96 where R: io::Read + 'a
97{
98
99 let i = to_minimap_bool(reader, settings)
100 .batching(move |i| {
101 let mut group : Vec<Vec<bool>> = Vec::new();
102 for _ in 0..BRAILLE_Y {
103 if let Some(line) = i.next() {
104 group.push(line);
105 } else {
106 break;
107 }
108 }
109 if group.is_empty() {
110 None
111 } else {
112 Some(group)
113 }
114 })
115 .map(move |group| {
117 let mut line_iters : Vec<_> = group
118 .iter()
119 .map(|line| line.iter()).collect();
120
121 let mut binary_column : Vec<u8> = Vec::new();
122
123
124 loop {
125 let mut finished = true;
127
128 let mut binary = 0;
129
130 for (row_i, mut line_iter) in line_iters.iter_mut().enumerate() {
131 if let Some(&printable) = line_iter.next() {
132 finished = false;
133 if printable {
134 binary |= 1 << row_i;
135 }
136 }
137 }
138
139 if finished {
140 break;
141 }
142
143 binary_column.push(binary)
144 }
145
146 binary_column
147 })
148 .map(|line| {
149 let mut s = String::new();
150
151 let mut iter = line.iter();
152 loop {
153 let bin1 = iter.next();
154 let bin2 = iter.next();
155
156 if bin1.is_none() && bin2.is_none() {
157 break;
158 }
159
160 let bin1 : u8 = *bin1.unwrap_or(&0);
161 let bin2 : u8 = *bin2.unwrap_or(&0);
162
163 debug_assert!(bin1 < 16);
164 debug_assert!(bin2 < 16);
165
166 let ch = LOOKUP_TABLE[(bin2 * 16 + bin1) as usize];
167 debug_assert_eq!(ch, byte_to_braillechar((bin2 * 16 + bin1)));
168 s.push(ch)
169 }
170
171 s
172 });
173
174 Box::new(i)
175}
176
177#[allow(unused)]
178fn to_minimap_stars<'a, R>(reader: R, settings: Settings) -> Box<Iterator<Item = String> + 'a>
179 where R: io::Read + 'a
180{
181
182 let i = to_minimap_bool(reader, settings)
183 .map(|dots| {
184 let v : Vec<_> = dots.iter().map(|&b| if b { "*" } else { " " }).collect();
185 let line : String = v.join("");
186 line
187 });
188
189 Box::new(i)
190}
191
192fn to_minimap_bool<'a, R>(reader: R,
193 settings: Settings)
194 -> Box<Iterator<Item = Vec<bool>> + 'a>
195 where R: io::Read + 'a
196{
197
198 let buf_reader = BufReader::new(reader);
199
200 let xscale = settings.xscale;
201 let yscale = settings.yscale;
202
203 let i = buf_reader
204 .lines()
205 .take_while(|b| b.is_ok())
206 .map(|b| b.unwrap())
207 .batching(move |i| {
209 let mut group : Vec<String> = Vec::new();
210 for _ in 0..yscale {
211 if let Some(line) = i.next() {
212 group.push(line);
213 } else {
214 break;
215 }
216 }
217 if group.is_empty() {
218 None
219 } else {
220 Some(group)
221 }
222 })
223 .map(move |group| {
224 let mut line_iters : Vec<_> = group
225 .iter()
226 .map(|line| UnicodeSegmentation::graphemes(line.as_str(), true)).collect();
227
228 let mut dots : Vec<bool> = Vec::new();
229 loop {
230 let mut in_this_column : Vec<bool> = Vec::new();
231 for line_iter in &mut line_iters {
232 let mut contains_nonwhite = None;
233
234 for _ in 0..xscale {
235 if let Some(glyph) = line_iter.next() {
236 if contains_nonwhite != Some(true) {
237 if glyph.chars().any(|ch| !ch.is_whitespace()) {
238 contains_nonwhite = Some(true);
239 } else {
240 contains_nonwhite = Some(false);
241 }
242 }
243 }
244 }
245
246 if let Some(nw) = contains_nonwhite {
247 in_this_column.push(nw)
248 }
249 }
250
251 if in_this_column.is_empty() {
252 break;
253 }
254
255 dots.push(in_this_column.iter().any(|&g| g ))
256 }
257 dots
258 });
259
260 Box::new(i)
261}
262
263#[derive(Clone)]
264pub struct Settings {
265 pub xscale: usize,
266 pub yscale: usize,
267}
268
269impl Settings {
270 pub fn new() -> Self {
271 Settings {
272 xscale: 1,
273 yscale: 1,
274 }
275 }
276}
277