diff options
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | README.md | 3 | ||||
| -rw-r--r-- | history.csv | 2 | ||||
| -rw-r--r-- | src/history.rs | 39 | ||||
| -rw-r--r-- | src/main.rs | 67 | ||||
| -rw-r--r-- | src/scramble.rs | 14 | ||||
| -rw-r--r-- | src/time.rs | 4 |
7 files changed, 102 insertions, 28 deletions
@@ -1 +1,2 @@ /target +*.backup diff --git a/README.md b/README.md new file mode 100644 index 0000000..527f937 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# rutikmer + +Rubik's cube timer. diff --git a/history.csv b/history.csv index 31a42e9..b57e579 100644 --- a/history.csv +++ b/history.csv @@ -1,4 +1,4 @@ -"time","scramble","date" +time,scramble,date 01:28.150,B2 F2 U2 R F2 D2 U2 R U2 L R B L R2 B' F2 D L2 F,2020-01-26 19:45:00 UTC 01:17.984,L D B R D' F2 L' D' R' B' D' R' L' U2 F2 L2 F2 R',2020-01-26 19:48:00 UTC 01:42.880,F' D2 B' U2 L2 D2 L2 B U2 F' D' B U B' F' R D2 B' F,2020-01-26 19:51:00 UTC diff --git a/src/history.rs b/src/history.rs index 3238543..6f03d44 100644 --- a/src/history.rs +++ b/src/history.rs @@ -6,7 +6,7 @@ /* By: charles <charles.cabergs@gmail.com> /o o \ */ /* / v \ */ /* Created: 2020/06/25 13:24:10 by charles / _ \ */ -/* Updated: 2020/06/25 13:24:12 by charles '-----------' */ +/* Updated: 2020/06/25 15:29:21 by charles '-----------' */ /* */ /* ************************************************************************** */ @@ -20,6 +20,7 @@ use chrono; use chrono::prelude::*; use super::scramble::Scramble; +use super::time::Timer; pub struct SolveTime(Duration); @@ -50,17 +51,23 @@ struct Entry { date: chrono::DateTime<Utc>, } -pub struct History(Vec<Entry>); +pub struct History { + entries: Vec<Entry>, + deleted: Vec<Entry>, +} const VEC_START_SIZE: usize = 200; impl History { pub fn from_csv(file_path: &str) -> History { - let mut history = History(Vec::with_capacity(VEC_START_SIZE)); + let mut history = History { + entries: Vec::with_capacity(VEC_START_SIZE), + deleted: Vec::new() + }; let mut reader = csv::Reader::from_path(file_path).unwrap(); for result in reader.records() { if let Ok(record) = result { - history.0.push(Entry{ + history.entries.push(Entry{ time: record[0].parse::<SolveTime>().unwrap(), scramble: record[1].parse::<Scramble>().unwrap(), date: record[2].parse::<chrono::DateTime<Utc>>().unwrap() @@ -73,7 +80,7 @@ impl History { pub fn save_csv(&self, file_path: &str) { let mut writter = csv::Writer::from_path(file_path).unwrap(); writter.write_record(&["time", "scramble", "date"]).unwrap(); - for entry in &self.0 { + for entry in &self.entries { writter.write_record(&[ entry.time.to_string(), entry.scramble.to_string(), @@ -84,6 +91,26 @@ impl History { } pub fn summarize(&self, n: usize) -> Vec<String> { - self.0.iter().skip(self.0.len() - n).map(|Entry{time, ..}| time.to_string()).collect() + self.entries.iter().skip(self.entries.len() - n).map(|Entry{time, ..}| time.to_string()).collect() + } + + pub fn pop(&mut self) { + if let Some(e) = self.entries.pop() { + self.deleted.push(e); + } + } + + pub fn undo_pop(&mut self) { + if let Some(e) = self.deleted.pop() { + self.entries.push(e); + } + } + + pub fn push(&mut self, timer: &Timer, scramble: &Scramble) { + self.entries.push(Entry { + time: SolveTime(timer.result), + scramble: scramble.clone(), + date: chrono::offset::Utc::now(), + }); } } diff --git a/src/main.rs b/src/main.rs index eab790e..f431ae7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,8 +5,8 @@ /* / \ */ /* By: charles <charles.cabergs@gmail.com> /o o \ */ /* / v \ */ -/* Created: 2020/06/25 11:42:17 by charles / _ \ */ -/* Updated: 2020/06/25 13:24:00 by charles '-----------' */ +/* Created: 2020/06/25 14:38:48 by charles / _ \ */ +/* Updated: 2020/06/25 15:35:58 by charles '-----------' */ /* */ /* ************************************************************************** */ @@ -37,6 +37,10 @@ const GREEN: Color = Color::RGB(0x1B, 0x5E, 0x20); const ORANGE: Color = Color::RGB(0xEF, 0x6C, 0x00); const BLACK: Color = Color::RGB(0x00, 0x00, 0x00); +const SCRAMBLE_LEN: usize = 14; +const SUMMARY_LEN: usize = 12; +const HISTORY_FILE_PATH: &str = "history.csv"; + fn str_to_tex<'a, T>(s: &str, font: &ttf::Font, creator: &'a TextureCreator<T>, bg: Color) -> Texture<'a> { let surface = font.render(s).shaded(WHITE, bg).unwrap(); creator.create_texture_from_surface(&surface).unwrap() @@ -47,6 +51,18 @@ fn pad_rect(rect: &mut Rect, pad: u32) { rect.offset(pad as i32 / 2, pad as i32 / 2); } +fn rect_text(frame: &Rect, len: usize) -> Rect { + let mut rect = *frame; + rect.set_width(len as u32 * FONT_SIZE); + rect.set_height(2 * FONT_SIZE); + if rect.width() > frame.width() { + rect.set_height(rect.height() * (rect.width() / frame.width())); + rect.set_width(frame.width()); + } + rect.center_on(frame.center()); + rect +} + fn main() { let sdl = sdl2::init().unwrap(); let ttf = ttf::init().unwrap(); @@ -55,14 +71,17 @@ fn main() { .window(TITLE, WIDTH, HEIGHT) .build() .unwrap(); + std::fs::copy(HISTORY_FILE_PATH, HISTORY_FILE_PATH.to_owned() + ".backup").unwrap(); let font = ttf.load_font("font/FiraMono-Regular.ttf", FONT_SIZE as u16).unwrap(); let mut canvas = window.into_canvas().build().unwrap(); let mut event_pump = sdl.event_pump().unwrap(); let tex_creator = canvas.texture_creator(); - let hist = History::from_csv("history.csv"); + let mut hist = History::from_csv(HISTORY_FILE_PATH); let mut timer = time::Timer::new(); - let mut scramble_tex = str_to_tex(&Scramble::new_rand(10).to_string(), &font, &tex_creator, BLACK); + let mut scramble = Scramble::new_rand(SCRAMBLE_LEN); + let mut scramble_str = scramble.to_string(); + let mut scramble_tex = str_to_tex(&scramble_str, &font, &tex_creator, BLACK); let mut timer_tex = str_to_tex(&timer.to_string(), &font, &tex_creator, BLACK); 'running: loop { @@ -73,12 +92,16 @@ fn main() { match timer.state { time::State::Inactive => { timer.idle(); - scramble_tex = str_to_tex(&Scramble::new_rand(10).to_string(), - &font, &tex_creator, BLACK); - timer_tex = str_to_tex(&timer.to_string(), &font, &tex_creator, BLACK); }, time::State::Idle => {}, - time::State::Active => timer.stop(), + time::State::Active => { + timer.stop(); + timer_tex = str_to_tex(&timer.to_string(), &font, &tex_creator, BLACK); + hist.push(&timer, &scramble); + scramble = Scramble::new_rand(SCRAMBLE_LEN); + scramble_str = scramble.to_string(); + scramble_tex = str_to_tex(&scramble_str, &font, &tex_creator, BLACK); + }, } } Event::KeyUp { keycode: Some(Keycode::Space), repeat: false, .. } => { @@ -86,6 +109,16 @@ fn main() { timer.start(); } }, + Event::KeyDown { keycode: Some(Keycode::D), repeat: false, .. } => { + if timer.state == time::State::Inactive { + hist.pop(); + } + }, + Event::KeyDown { keycode: Some(Keycode::U), repeat: false, .. } => { + if timer.state == time::State::Inactive { + hist.undo_pop(); + } + }, _ => {} } } @@ -99,7 +132,6 @@ fn main() { match timer.state { time::State::Inactive => { - let mut history_rect = Rect::new(0, 0, WIDTH/ 3, HEIGHT); let mut scramble_rect = Rect::new(WIDTH as i32 / 3, 0, 2 * WIDTH / 3, HEIGHT / 3); let mut timer_rect = Rect::new(WIDTH as i32 / 3, HEIGHT as i32 / 3, @@ -112,19 +144,19 @@ fn main() { pad_rect(&mut history_rect, 10); pad_rect(&mut scramble_rect, 20); pad_rect(&mut timer_rect, 40); - scramble_rect.set_height(FONT_SIZE * 2); - timer_rect.set_height(FONT_SIZE * 2); - timer_rect.set_width(timer.to_string().len() as u32 * FONT_SIZE); - canvas.copy(&scramble_tex, None, scramble_rect).unwrap(); - canvas.copy(&timer_tex, None, timer_rect).unwrap(); + let scramble_text_rect = rect_text(&scramble_rect, scramble_str.len()); + let timer_text_rect = rect_text(&timer_rect, timer.to_string().len()); + + canvas.copy(&scramble_tex, None, scramble_text_rect).unwrap(); + canvas.copy(&timer_tex, None, timer_text_rect).unwrap(); let mut entry_rect = history_rect; - entry_rect.set_height(entry_rect.height() / 5); - for entry in hist.summarize(5) { + entry_rect.set_height(history_rect.height() / SUMMARY_LEN as u32); + for entry in hist.summarize(SUMMARY_LEN) { let entry_tex = str_to_tex(&entry.to_string(), &font, &tex_creator, BLACK); canvas.copy(&entry_tex, None, entry_rect).unwrap(); - entry_rect.set_y(entry_rect.y() + history_rect.height() as i32 / 5); + entry_rect.set_y(entry_rect.y() + history_rect.height() as i32 / SUMMARY_LEN as i32); } }, time::State::Idle => {}, @@ -145,6 +177,7 @@ fn main() { std::thread::sleep(std::time::Duration::new(0, 10_000_000)); } } + hist.save_csv(HISTORY_FILE_PATH); } /* inactive (all black) diff --git a/src/scramble.rs b/src/scramble.rs index 061341e..b718cc5 100644 --- a/src/scramble.rs +++ b/src/scramble.rs @@ -6,7 +6,7 @@ /* By: charles <charles.cabergs@gmail.com> /o o \ */ /* / v \ */ /* Created: 2020/06/25 13:24:17 by charles / _ \ */ -/* Updated: 2020/06/25 13:24:18 by charles '-----------' */ +/* Updated: 2020/06/25 15:29:01 by charles '-----------' */ /* */ /* ************************************************************************** */ @@ -18,6 +18,7 @@ use rand::{ Rng }; +#[derive(Clone)] pub struct Scramble(Vec<Move>); impl Scramble { @@ -57,6 +58,13 @@ impl str::FromStr for Scramble { } } +// impl Clone for Scramble { +// fn clone(&self) -> Scramble { +// let v = self.0; +// Scramble(v) +// } +// } + impl str::FromStr for Move { type Err = &'static str; fn from_str(s: &str) -> Result<Self, Self::Err> { @@ -87,11 +95,13 @@ impl str::FromStr for Move { } } -#[derive(PartialEq)] +#[derive(PartialEq, Clone)] enum Direction { Front, Back, Down, Up, Right, Left, } +#[derive(Clone)] enum Modifier { No, Twice, Prime, } +#[derive(Clone)] struct Move { direction: Direction, modifier: Modifier, diff --git a/src/time.rs b/src/time.rs index e9fabe9..76cc04e 100644 --- a/src/time.rs +++ b/src/time.rs @@ -6,7 +6,7 @@ /* By: charles <charles.cabergs@gmail.com> /o o \ */ /* / v \ */ /* Created: 2020/06/25 13:24:24 by charles / _ \ */ -/* Updated: 2020/06/25 13:24:24 by charles '-----------' */ +/* Updated: 2020/06/25 15:23:01 by charles '-----------' */ /* */ /* ************************************************************************** */ @@ -22,7 +22,7 @@ pub enum State { pub struct Timer { pub state: State, time: SystemTime, - result: Duration, + pub result: Duration, } impl Timer { |
