use std::fmt::Write as _;
const WIDTH: usize = 42;
const HEIGHT: usize = 17;
const FRAME_COUNT: usize = 4;
const MIN_WIDTH: u16 = 28;
const PALETTE: [u8; 16] = [
0, 234, 237, 240, 244, 95, 138, 131, 181, 174, 187, 255, 23, 51, 198, 167,
];
const GLYPHS: [char; 10] = [' ', '.', ':', '-', '=', '+', '*', '#', '%', '@'];
#[derive(Clone, Copy)]
pub(crate) enum Pose {
Cursor = 0,
Blink = 1,
Scratch = 2,
Idle = 3,
}
pub(crate) fn render(pose: Pose, columns: u16, color: bool) -> Option<String> {
render_frame(pose, columns, color, false)
}
pub(crate) fn render_alive(pose: Pose, columns: u16, color: bool) -> Option<String> {
render_frame(pose, columns, color, true)
}
fn render_frame(pose: Pose, columns: u16, color: bool, alive: bool) -> Option<String> {
if !color || columns < MIN_WIDTH {
return None;
}
let width = usize::from(columns).min(WIDTH);
let height = (width * HEIGHT).div_ceil(WIDTH);
let mut output = String::with_capacity(width * height * 8);
for y in 0..height {
let source_y = y * HEIGHT / height;
let last = (0..width)
.rposition(|x| pixel(pose, source_y, x * WIDTH / width) != 0)
.unwrap_or_default();
let mut previous = (0, 0);
for x in 0..=last {
let source_x = x * WIDTH / width;
let value = pixel(pose, source_y, source_x);
let color = usize::from(value >> 4);
let motion = if alive && eye(source_y, source_x) {
5
} else if alive && matches!(pose, Pose::Scratch) && itch(source_y, source_x) {
6
} else {
0
};
if (color, motion) != previous {
if color == 0 {
output.push_str("\x1b[0m");
} else if motion > 0 {
let _ = write!(output, "\x1b[0;{motion};38;5;{}m", PALETTE[color]);
} else {
let _ = write!(output, "\x1b[0;38;5;{}m", PALETTE[color]);
}
previous = (color, motion);
}
output.push(GLYPHS[usize::from(value & 0x0f)]);
}
if previous != (0, 0) {
output.push_str("\x1b[0m");
}
if y + 1 != height {
output.push('\n');
}
}
Some(output)
}
fn eye(y: usize, x: usize) -> bool {
matches!((y, x), (5, 31 | 37) | (6, 31 | 32 | 37))
}
fn itch(y: usize, x: usize) -> bool {
(2..=8).contains(&y) && x >= 34 && pixel(Pose::Scratch, y, x) != pixel(Pose::Cursor, y, x)
}
pub(crate) fn loading_frames(columns: u16, color: bool, motion: bool) -> Vec<String> {
let width = columns.min(30);
let Some(idle) = render(Pose::Cursor, width, color) else {
let frames = if motion {
&["▹ P0SSUM//", "▸ POS_SUM//", "▹ POSSUM//", "▸ POSSUM//"][..]
} else {
&["POSSUM//", "POSSUM//"][..]
};
return frames.iter().map(|frame| (*frame).to_owned()).collect();
};
if !motion {
return vec![idle.clone(), idle];
}
let blink = render(Pose::Blink, width, color).unwrap_or_else(|| idle.clone());
let scratch = render(Pose::Scratch, width, color).unwrap_or_else(|| idle.clone());
vec![
idle.clone(),
blink,
idle.clone(),
scratch.clone(),
scratch,
idle.clone(),
idle.clone(),
idle.clone(),
idle.clone(),
idle,
]
}
fn pixel(pose: Pose, y: usize, x: usize) -> u8 {
let row = FRAMES[pose as usize][y].as_bytes();
(hex(row[x * 2]) << 4) | hex(row[x * 2 + 1])
}
fn hex(value: u8) -> u8 {
match value {
b'0'..=b'9' => value - b'0',
b'a'..=b'f' => value - b'a' + 10,
_ => 0,
}
}
const FRAMES: [[&str; HEIGHT]; FRAME_COUNT] = [
[
"000000000000000000000000000000000000000000000000001124241200000000000000000000000000",
"000000000000000000000000000011121424242424242412222838282834121100000000000011121200",
"000000000000000000000011c43838383847575838382828283838777738193838242212243838283824",
"00000000000000000000c43838585747666747573828282829a686f7f728198666282838197877583811",
"000000000000000011c8385858474767676647383838572829666767662886666686285766587786f200",
"0000000000000011c857385757574747676657385757573828678657a657282938b54766662877f20000",
"00000000000011c8385738383828586767675738574747475857b5b58686281919a566672819f7000000",
"000000000000c438584767675758383857666728674758576686a5b5b5b5b58657679667388662003100",
"0000000000c2385847474747678686664767a567574758383867a5b5b5a686a566779697746251710000",
"0000000011c838573838383838574786a567a5b567573857575757a6a586675758521111000000000000",
"00000011c8283857573838382838574786a666b5b5a64738585757678628192838540000000000000000",
"0000346667582857675728283838385786a5676767475728243857578654222857777422000000000000",
"314686f75422242434282819282838576686281928282822001124384766525174779696f40000000000",
"4485972100000011525474512114283858382219283877f7777200125857579472512222000000000000",
"21978574000000000021f48672001438587767947772f152543411003277677754000000000000000000",
"002174969694725252f49697220000002174546767540000000000000000110000000000000000000000",
"000000002132545454522200000000000000001100000000000000000000000000000000000000000000",
],
[
"000000000000000000000000000000000000000000000000001124241200000000000000000000000000",
"000000000000000000000000000011121424242424242412222838282824121100000000000011121100",
"000000000000000000000011c42838383847575838382829283838777738192838242212243838283822",
"00000000000000000000c23838575747666747573828282829a686f7f728196666282858197877583811",
"000000000000000011c43858584747676667673838385728296667676638668666672957675877867200",
"0000000000000011c8373858575747476766573857575738286786578657575766b55766865877f20000",
"00000000000000c8385738383838586767675738584747475857b5b58667475738a56667575874000000",
"000000000000c438584767675757383857666728474758576786a5b5b5b5b58658679667388662005100",
"0000000000c2c83847474757478686664767a567574758385867a6b5b5a686a5666796f7746251510000",
"0000000000c838583838383838574786a567a5b56757385757575786a586665758721111000000000000",
"00000011c4283857573838382838574786a566b5b5865738585757678628192938540000000000000000",
"0000326697582857475728383838385786a5676767475728242858578654222857777421000000000000",
"216686f75422242438282919283838576686282928282851001124384766523154779696720000000000",
"22a59751000000115254745131142838583822192838779797f200125857779472512222000000000000",
"11978694210000000021f485520024285877979777725122343411003277676754000000000000000000",
"001174979694723252749697220000001174576767540000000000000000110000000000000000000000",
"000000002132547454522211000000000000001100000000000000000000000000000000000000000000",
],
[
"000000000000000000000000000000000000000000000000000000222424220000000000000000000000",
"000000000000000000000000000000111212121212111100000024283828382200000000000000000000",
"00000000000000000000001112c438283857573838282828242437385777382812000000000000000000",
"00000000000000000011c4383858585767675757382828281947b597f7f7581938382412122224282412",
"0000000000000000c2c83858574747666667473828285828388696776728384766382928195858383824",
"00000000000000c2c838585757674747666638385758282886a577574747676686571957587867672400",
"000000000000c2c857583858583847666657384757574767573867a667191928b5674786573886520000",
"000000000011c838574747573838385767473847576747382957b5a5a5572947a547662929f721000000",
"0000000000c838574767676767866647578666383828283847668686a5a5776696673857677100000000",
"0000000022c8385757385838576767868667a5b58666668686866666674757f7967764926171e1000000",
"00000021c82857583838382838385767868666b5b5b5a586866647382819285872005100000000000000",
"0000326777383847475828383838385766a5676786666747585812121428385858720000000000000000",
"116686f7742428385838281928283858678657292828282828210000001112589797f452000000000000",
"328597510000003134575452222428385838322219283858f79774210000002254676797510000000000",
"11f78694210000000021f486740012283857779494747211323454210000000000111100000000000000",
"001172979694743252f29696520000001154546767742100000000000000000000000000000000000000",
"000000002132545454322211000000000000001111000000000000000000000000000000000000000000",
],
[
"000000000000000000000000000000000000000000000000001124241200000000000000000000000000",
"000000000000000000000000000011122424242424242412222838282824121100000000000011121100",
"000000000000000000000011c42838383847575838382828283838777738193838242212243838283822",
"00000000000000000000c23838585747666747573828283829a686f7f738198666292838197777582821",
"000000000000000011c43858584747676667673838385738296766676628866666862847665877867200",
"0000000000000021c857585757574747676647385757573828678657a547282938b54766672877720000",
"00000000000011c8385738383838586766675738584747475857b5b58686281919a666672829f4000000",
"000000000000c438584767675758383857666728474758576686a5b5b5b5b58657679667588662005100",
"0000000000c2c85847474747478686665767a567574758585867a5b5b5a586a566779696746271710000",
"0000000011c838573838583838576786a567a5b56757385757575786a586665758521111000051000000",
"00000011c82838575738383838385747868666b5b5865738385757678628192938540000000000000000",
"0000346697582857675728383838384786a5676767475728243857578654222857777451000000000000",
"316686f77422242434282819283838576686281929282811001114384766523154779696720000000000",
"528596110000001154547451211428385838221928387777f7f20022385757f772312222000000000000",
"11f786942100000000217486720014385877979477727152343421003477676754000000000000000000",
"001132969694f45232749697520000002174576767540000000000000000110000000000000000000000",
"000000002132545454522200000000000000001100000000000000000000000000000000000000000000",
],
];