Rework order of primes and saved state to get deterministic output
This commit is contained in:
parent
04f554f29c
commit
bc31197653
@ -15,3 +15,5 @@ rand = "0.8.4"
|
|||||||
chrono = "0.4.6"
|
chrono = "0.4.6"
|
||||||
lowdim = { version = "0.6.0", features = ["random"] }
|
lowdim = { version = "0.6.0", features = ["random"] }
|
||||||
primal = "0.3.3"
|
primal = "0.3.3"
|
||||||
|
serde = { version = "1.0.215", features = ["derive"] }
|
||||||
|
serde_json = "1.0.132"
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
use std::cmp;
|
||||||
|
use std::collections::BinaryHeap;
|
||||||
use std::env::args;
|
use std::env::args;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io::stdout;
|
use std::io::stdout;
|
||||||
@ -5,6 +7,9 @@ use std::io::Write;
|
|||||||
use std::thread::sleep;
|
use std::thread::sleep;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use serde::Deserialize;
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
use lowdim::bb2d;
|
use lowdim::bb2d;
|
||||||
use lowdim::p2d;
|
use lowdim::p2d;
|
||||||
use lowdim::v2d;
|
use lowdim::v2d;
|
||||||
@ -151,13 +156,52 @@ const DEFAULT_ARG: u64 = 2;
|
|||||||
|
|
||||||
const STATE_FILENAME: &str = ".primes.state";
|
const STATE_FILENAME: &str = ".primes.state";
|
||||||
|
|
||||||
fn write_state(p: usize) {
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
let _ = fs::write(STATE_FILENAME, p.to_string());
|
struct State {
|
||||||
|
prime: usize,
|
||||||
|
xs: Vec<i64>,
|
||||||
|
}
|
||||||
|
impl State {
|
||||||
|
fn init(len: usize, x: i64) -> State {
|
||||||
|
State {
|
||||||
|
prime: 2,
|
||||||
|
xs: vec![x; len],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn load(lines: usize) -> Result<State> {
|
||||||
|
let s = fs::read_to_string(STATE_FILENAME)?;
|
||||||
|
let state: State = serde_json::from_str(&s)?;
|
||||||
|
if state.xs.len() != lines {
|
||||||
|
return Err("number of lines don't match".into());
|
||||||
|
}
|
||||||
|
Ok(state)
|
||||||
|
}
|
||||||
|
fn save(&self) -> Result<()> {
|
||||||
|
let serialized = serde_json::to_string(self)?;
|
||||||
|
Ok(fs::write(STATE_FILENAME, serialized)?)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_state() -> Result<usize> {
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
let s = fs::read_to_string(STATE_FILENAME)?;
|
struct LinePos {
|
||||||
Ok(s.parse::<usize>()?)
|
/// Index of the line.
|
||||||
|
index: usize,
|
||||||
|
/// Rendering position in this line.
|
||||||
|
pos: Point2d,
|
||||||
|
}
|
||||||
|
impl PartialOrd for LinePos {
|
||||||
|
fn partial_cmp(&self, other: &LinePos) -> Option<cmp::Ordering> {
|
||||||
|
Some(self.cmp(other))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Ord for LinePos {
|
||||||
|
fn cmp(&self, other: &Self) -> cmp::Ordering {
|
||||||
|
other
|
||||||
|
.pos
|
||||||
|
.x()
|
||||||
|
.cmp(&self.pos.x())
|
||||||
|
.then(self.index.cmp(&other.index))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
@ -178,10 +222,6 @@ fn main() -> Result<()> {
|
|||||||
let x_size = i64::try_from(x_size)?;
|
let x_size = i64::try_from(x_size)?;
|
||||||
let y_size = i64::try_from(y_size)?;
|
let y_size = i64::try_from(y_size)?;
|
||||||
|
|
||||||
let last_prime = read_state().unwrap_or(1);
|
|
||||||
eprintln!("starting after {}", last_prime);
|
|
||||||
let mut primes_iter = primal::Primes::all().skip_while(|&p| p < last_prime);
|
|
||||||
|
|
||||||
let bbox = bb2d(0..x_size as i64, 0..y_size as i64);
|
let bbox = bb2d(0..x_size as i64, 0..y_size as i64);
|
||||||
|
|
||||||
let mut frame = Frame::new(bbox);
|
let mut frame = Frame::new(bbox);
|
||||||
@ -198,60 +238,96 @@ fn main() -> Result<()> {
|
|||||||
MIN_LINE_SEP
|
MIN_LINE_SEP
|
||||||
};
|
};
|
||||||
let line_sep = line_sep.max(MIN_LINE_SEP);
|
let line_sep = line_sep.max(MIN_LINE_SEP);
|
||||||
|
let x0 = bbox.x_start() + MIN_MARGIN;
|
||||||
let y0 = MIN_MARGIN + (y_size - 2 * MIN_MARGIN - lines * HEIGHT - (lines - 1) * line_sep) / 2;
|
let y0 = MIN_MARGIN + (y_size - 2 * MIN_MARGIN - lines * HEIGHT - (lines - 1) * line_sep) / 2;
|
||||||
let mut start_positions = (0..lines)
|
let line_count = usize::try_from(lines)?;
|
||||||
.map(|i| p2d(bbox.x_end(), y0 + i * (line_sep + HEIGHT)))
|
|
||||||
|
let start_state = State::load(line_count).unwrap_or_else(|_| State::init(line_count, x0));
|
||||||
|
eprintln!("starting at {}", start_state.prime);
|
||||||
|
|
||||||
|
let mut primes_iter = primal::Primes::all().skip_while(|&p| p < start_state.prime);
|
||||||
|
|
||||||
|
let mut start_positions = start_state
|
||||||
|
.xs
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(i, &x)| p2d(x, y0 + (i as i64) * (line_sep + HEIGHT)))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let lines = usize::try_from(lines)?;
|
let mut visible_primes = Vec::new();
|
||||||
|
|
||||||
let mut visible_primes = (0..lines).map(|_| Vec::new()).collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let space = v2d(2, 0);
|
let space = v2d(2, 0);
|
||||||
loop {
|
loop {
|
||||||
let mut new_frame = Frame::new(bbox);
|
let mut new_frame = Frame::new(bbox);
|
||||||
let mut new_visible_primes = (0..lines).map(|_| Vec::new()).collect::<Vec<_>>();
|
let mut new_visible_primes = Vec::new();
|
||||||
|
|
||||||
for i in (0..lines).rev() {
|
// Fill empty space from the left to the right over all lines.
|
||||||
let mut pos = start_positions[i];
|
let mut positions = start_positions
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(i, &pos)| LinePos { index: i, pos })
|
||||||
|
.collect::<BinaryHeap<_>>();
|
||||||
|
// Render the primes that are already visible.
|
||||||
|
for p in visible_primes {
|
||||||
|
let line_pos = positions.pop().unwrap();
|
||||||
|
let i = line_pos.index;
|
||||||
|
let mut pos = line_pos.pos;
|
||||||
|
|
||||||
|
render(&mut new_frame, &mut pos, p);
|
||||||
|
if new_visible_primes.is_empty() && pos.x() + STROKE_MID < frame.bbox().x_start() {
|
||||||
|
// The prime is not visible any more,
|
||||||
|
// not even some overhang from a five bar.
|
||||||
|
// Omit it from the visible primes and move the start position
|
||||||
|
// to the start of the next number.
|
||||||
|
// Only do this if no previous prime was kept.
|
||||||
|
start_positions[i] = pos + space;
|
||||||
|
} else {
|
||||||
|
// Keep the prime for displaying it the next time.
|
||||||
|
new_visible_primes.push(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render a space between numbers.
|
||||||
|
pos += space;
|
||||||
|
|
||||||
|
// Save the new position for later handling.
|
||||||
|
positions.push(LinePos { index: i, pos });
|
||||||
|
}
|
||||||
|
while let Some(line_pos) = positions.pop() {
|
||||||
|
let i = line_pos.index;
|
||||||
|
let mut pos = line_pos.pos;
|
||||||
|
|
||||||
|
// Fill up the visible primes when necessary.
|
||||||
|
if pos.x() < frame.bbox().x_end() + STROKE_MID {
|
||||||
|
let p = primes_iter.next().unwrap();
|
||||||
|
eprintln!("{} {}", i, p);
|
||||||
|
|
||||||
|
// Keep the prime for displaying it the next time.
|
||||||
|
new_visible_primes.push(p);
|
||||||
|
|
||||||
// Render the primes that are already visible.
|
|
||||||
for &p in &visible_primes[i] {
|
|
||||||
render(&mut new_frame, &mut pos, p);
|
render(&mut new_frame, &mut pos, p);
|
||||||
if pos.x() + STROKE_MID < frame.bbox().x_start() {
|
|
||||||
// The prime is not visible any more,
|
|
||||||
// not even some overhang from a five bar.
|
|
||||||
// Omit it from the visible primes and move the start position
|
|
||||||
// to the start of the next number.
|
|
||||||
start_positions[i] = pos + space;
|
|
||||||
} else {
|
|
||||||
// Keep the prime for displaying it the next time.
|
|
||||||
new_visible_primes[i].push(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Render a space between numbers.
|
// Render a space between numbers.
|
||||||
pos += space;
|
pos += space;
|
||||||
|
|
||||||
|
positions.push(LinePos { index: i, pos });
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Fill up the visible primes when necessary.
|
// Scroll one pixel to the left.
|
||||||
while pos.x() < frame.bbox().x_end() + STROKE_MID {
|
for pos in &mut start_positions {
|
||||||
let p = primes_iter.next().unwrap();
|
*pos -= v2d(1, 0);
|
||||||
write_state(p);
|
|
||||||
eprintln!("{}", p);
|
|
||||||
|
|
||||||
// Keep the prime for displaying it the next time.
|
|
||||||
new_visible_primes[i].push(p);
|
|
||||||
|
|
||||||
render(&mut new_frame, &mut pos, p);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scroll one pixel to the left.
|
|
||||||
start_positions[i] -= v2d(1, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
frame = new_frame;
|
frame = new_frame;
|
||||||
visible_primes = new_visible_primes;
|
visible_primes = new_visible_primes;
|
||||||
|
|
||||||
|
// Save the state
|
||||||
|
let state = State {
|
||||||
|
prime: visible_primes[0],
|
||||||
|
xs: start_positions.iter().map(|p| p.x()).collect::<Vec<_>>(),
|
||||||
|
};
|
||||||
|
let _ = state.save();
|
||||||
|
|
||||||
let mut buf = Vec::with_capacity(frame_size);
|
let mut buf = Vec::with_capacity(frame_size);
|
||||||
send(&mut buf, &frame)?;
|
send(&mut buf, &frame)?;
|
||||||
stdout().write_all(&buf)?;
|
stdout().write_all(&buf)?;
|
||||||
|
Loading…
Reference in New Issue
Block a user