Skip to content

Commit 339f31b

Browse files
committed
Add visualization label for current Collatz number and implement small bitmap text rendering
1 parent 81b8cf9 commit 339f31b

File tree

1 file changed

+106
-0
lines changed

1 file changed

+106
-0
lines changed

src/main.rs

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,7 @@ fn run_viz(rx: Receiver<VizMsg>, max_steps: usize) {
322322
let mut buffer = vec![0u32; VIZ_W * VIZ_H];
323323
// Streaming animation state
324324
let mut current_n: Option<BigUint> = None;
325+
let mut current_label: Option<String> = None;
325326
let mut bits_window: VecDeque<usize> = VecDeque::with_capacity(max_steps.max(1));
326327
let max_points = max_steps.max(1);
327328
let steps_per_tick: usize = (max_points / 60).clamp(1, 2000);
@@ -349,6 +350,7 @@ fn run_viz(rx: Receiver<VizMsg>, max_steps: usize) {
349350
match msg {
350351
VizMsg::Draw(start) => {
351352
// Begin animating this trajectory from scratch
353+
current_label = Some(short_decimal(&start, 12, 12));
352354
current_n = Some(start);
353355
bits_window.clear();
354356
should_redraw = true;
@@ -373,6 +375,8 @@ fn run_viz(rx: Receiver<VizMsg>, max_steps: usize) {
373375
// If we reached 1 and didn't receive a new start, pick a fallback sample
374376
if *n == one && !had_new_draw {
375377
*n = vrng.gen_range_biguint(&rand_low, &rand_high_inclusive);
378+
// Update the on-screen label for the new start
379+
current_label = Some(short_decimal(&*n, 12, 12));
376380
bits_window.clear();
377381
}
378382
should_redraw = true;
@@ -397,6 +401,17 @@ fn run_viz(rx: Receiver<VizMsg>, max_steps: usize) {
397401
prev = curr;
398402
}
399403

404+
// Draw seed label bottom-left with heading
405+
if let Some(ref lbl) = current_label {
406+
let scale_num: i32 = 2; // make number larger
407+
let num_h = (SMALL_FONT_H as i32) * scale_num;
408+
let gap = 4;
409+
let num_y = (VIZ_H as i32) - 10 - num_h;
410+
let heading_y = (num_y - gap - SMALL_FONT_H as i32).max(0);
411+
draw_text_small(&mut buffer, 12, heading_y, "NUMBER BEING TESTED:", 0xFF000000);
412+
draw_text_small_scaled(&mut buffer, 12, num_y, lbl, 0xFF000000, scale_num as usize);
413+
}
414+
400415
let _ = window.update_with_buffer(&buffer, VIZ_W, VIZ_H);
401416
} else {
402417
window.update();
@@ -466,6 +481,97 @@ fn draw_axes(buf: &mut [u32], pad: usize, color: u32) {
466481
for y in y0..=y1 { buf[y * VIZ_W + x0] = color; }
467482
}
468483

484+
// ---------- Small bitmap text rendering for digits and '.' ----------
485+
const SMALL_FONT_W: usize = 5;
486+
const SMALL_FONT_H: usize = 7;
487+
488+
fn draw_text_small(buf: &mut [u32], x: i32, y: i32, text: &str, color: u32) {
489+
let mut cx = x;
490+
for ch in text.chars() {
491+
if let Some(g) = glyph_for(ch) {
492+
draw_glyph_small(buf, cx, y, &g, color);
493+
cx += (SMALL_FONT_W as i32) + 2; // 1px spacing
494+
} else if ch == ' ' {
495+
cx += (SMALL_FONT_W as i32) + 2;
496+
}
497+
}
498+
}
499+
500+
fn draw_glyph_small(buf: &mut [u32], x: i32, y: i32, glyph: &[u8; SMALL_FONT_H], color: u32) {
501+
for (row, bits) in glyph.iter().enumerate() {
502+
for col in 0..SMALL_FONT_W {
503+
// Bits are in lower 5 bits of the byte; MSB of 5 at position 4
504+
let on = (bits >> (SMALL_FONT_W as u8 - 1 - col as u8)) & 1 == 1;
505+
if on { plot(x + col as i32, y + row as i32, color, buf); }
506+
}
507+
}
508+
}
509+
510+
fn draw_text_small_scaled(buf: &mut [u32], x: i32, y: i32, text: &str, color: u32, scale: usize) {
511+
let s = scale.max(1) as i32;
512+
let mut cx = x;
513+
for ch in text.chars() {
514+
if ch == ' ' { cx += (SMALL_FONT_W as i32 + 2) * s; continue; }
515+
if let Some(g) = glyph_for(ch) {
516+
draw_glyph_small_scaled(buf, cx, y, &g, color, s as usize);
517+
cx += ((SMALL_FONT_W as i32) + 2) * s;
518+
}
519+
}
520+
}
521+
522+
fn draw_glyph_small_scaled(buf: &mut [u32], x: i32, y: i32, glyph: &[u8; SMALL_FONT_H], color: u32, scale: usize) {
523+
let s = scale.max(1) as i32;
524+
for (row, bits) in glyph.iter().enumerate() {
525+
for col in 0..SMALL_FONT_W {
526+
let on = (bits >> (SMALL_FONT_W as u8 - 1 - col as u8)) & 1 == 1;
527+
if on {
528+
for dy in 0..s {
529+
for dx in 0..s {
530+
plot(x + col as i32 * s + dx, y + row as i32 * s + dy, color, buf);
531+
}
532+
}
533+
}
534+
}
535+
}
536+
}
537+
538+
fn glyph_for(ch: char) -> Option<[u8; SMALL_FONT_H]> {
539+
match ch {
540+
'0' => Some([0b01110,0b10001,0b10011,0b10101,0b11001,0b10001,0b01110]),
541+
'1' => Some([0b00100,0b01100,0b00100,0b00100,0b00100,0b00100,0b01110]),
542+
'2' => Some([0b01110,0b10001,0b00001,0b00010,0b00100,0b01000,0b11111]),
543+
'3' => Some([0b01110,0b10001,0b00001,0b00110,0b00001,0b10001,0b01110]),
544+
'4' => Some([0b00010,0b00110,0b01010,0b10010,0b11111,0b00010,0b00010]),
545+
'5' => Some([0b11111,0b10000,0b11110,0b00001,0b00001,0b10001,0b01110]),
546+
'6' => Some([0b00110,0b01000,0b10000,0b11110,0b10001,0b10001,0b01110]),
547+
'7' => Some([0b11111,0b00001,0b00010,0b00100,0b01000,0b01000,0b01000]),
548+
'8' => Some([0b01110,0b10001,0b10001,0b01110,0b10001,0b10001,0b01110]),
549+
'9' => Some([0b01110,0b10001,0b10001,0b01111,0b00001,0b00010,0b11100]),
550+
'.' => Some([0b00000,0b00000,0b00000,0b00000,0b00000,0b00100,0b00100]),
551+
':' => Some([0b00000,0b00100,0b00100,0b00000,0b00100,0b00100,0b00000]),
552+
'N' => Some([0b10001,0b11001,0b10101,0b10011,0b10001,0b10001,0b00000]),
553+
'U' => Some([0b10001,0b10001,0b10001,0b10001,0b10001,0b01110,0b00000]),
554+
'M' => Some([0b10001,0b11011,0b10101,0b10101,0b10001,0b10001,0b00000]),
555+
'B' => Some([0b11110,0b10001,0b10001,0b11110,0b10001,0b10001,0b11110]),
556+
'E' => Some([0b11111,0b10000,0b10000,0b11110,0b10000,0b10000,0b11111]),
557+
'R' => Some([0b11110,0b10001,0b10001,0b11110,0b10100,0b10010,0b10001]),
558+
'I' => Some([0b01110,0b00100,0b00100,0b00100,0b00100,0b00100,0b01110]),
559+
'G' => Some([0b01110,0b10001,0b10000,0b10111,0b10001,0b10001,0b01110]),
560+
'T' => Some([0b11111,0b00100,0b00100,0b00100,0b00100,0b00100,0b00100]),
561+
'S' => Some([0b01111,0b10000,0b10000,0b01110,0b00001,0b00001,0b11110]),
562+
'D' => Some([0b11110,0b10001,0b10001,0b10001,0b10001,0b10001,0b11110]),
563+
_ => None,
564+
}
565+
}
566+
567+
fn short_decimal(n: &BigUint, head: usize, tail: usize) -> String {
568+
let s = n.to_str_radix(10);
569+
if s.len() <= head + tail + 3 { return s; }
570+
let start = &s[..head.min(s.len())];
571+
let end = &s[s.len()-tail.min(s.len())..];
572+
format!("{}...{}", start, end)
573+
}
574+
469575
fn main() {
470576
if let Err(e) = real_main() {
471577
eprintln!("error: {e}");

0 commit comments

Comments
 (0)