Этот точно как раз для моего часового пояса — в отличие от вчера-сегодня…
Синтаксический анализ выглядит намного проще во второй день — просто серия строк с 2 символами (3, если вы включаете пробел между ними, 4 с новой строкой) и 3 возможности для каждого символа. С учетом сказанного, я думаю, что мое решение здесь немного странное. Но я начну с кода парсинга — надеюсь, здесь не так много нового:
pub fn read_from_system(path: &str) -> Vec<[u8;3]> { let mut v: Vec<[u8;3]> = Vec::with_capacity(2600); // There are ~2500 lines in the input so this should definitely be enough let mut hold_buf: [u8;BUF_SIZE*2] = [0;BUF_SIZE*2]; let mut read = 0; // Read into buffer, scan for double newline, then parse the previous items and sum them into a single value unsafe { let fh = syscall!(OPEN,path.as_ptr(),0,path.len()); while read == 0 { let mut buf: [u8;BUF_SIZE] = [0;BUF_SIZE]; read = syscall!(READ, fh, buf.as_ptr(), BUF_SIZE); parse_block(&mut buf, &mut v, &mut hold_buf); } syscall!(CLOSE,fh); } return v; } fn parse_block(b :&mut [u8;BUF_SIZE], v: &mut Vec<[u8;3]> , hb: &mut [u8;BUF_SIZE*2]){ let mut raw_lines = Vec::new(); add_old_chars(&mut raw_lines, hb); // Logic dictates raw elf does not have a full elf in it yet *hb = [0;BUF_SIZE*2]; get_lines(b, v); } fn get_lines(b: &mut [u8;BUF_SIZE], v: &mut Vec<[u8;3]>) { let mut line_buf = Vec::with_capacity(3); for char in b { if char == &NEW_LINE { let line = [line_buf[0],line_buf[1],line_buf[2]]; v.push(line); line_buf.clear() } else { line_buf.push(*char); } } } fn add_old_chars(v: &mut Vec<u8>, c: &mut [u8;BUF_SIZE*2]) { for item in c { if item == &0 { break } else { v.push(*item) } } }
Это то же самое, что и день 1, но намного проще и нет двойных новых строк, которые нужно проверять. На этот раз имеет смысл сохранить все как u8. Для этой головоломки я ввел несколько констант и перечисление. Однако часть 1 и часть 2 не следуют единому методу:
const ROCK: u8 = b'A'; const PAPER: u8 = b'B'; const SCIS: u8 = b'C'; const MY_ROCK: u8 = b'X'; const MY_PAPER: u8 = b'Y'; const MY_SCIS: u8 = b'Z'; const LOSE: u8 = b'X'; const DRAW: u8 = b'Y'; const WIN: u8 = b'Z'; enum Outcome { Win, Lose, Draw } fn parse_line(buf: &[u8]) -> (Outcome, u8) { // Returns a bool for won/lost and a u8 for choice score (not total score!) let elf_choice = buf[0]; let my_choice = buf[2]; let choice_score = match my_choice { MY_ROCK => 1, MY_PAPER => 2, MY_SCIS => 3, _ => panic!("Invalid choice! {}", my_choice) }; let res = rps(my_choice,elf_choice); return (res,choice_score) } fn rps(me:u8,elf:u8) -> Outcome { match me { MY_ROCK => { match elf { ROCK => return Outcome::Draw, PAPER => return Outcome::Lose, SCIS => return Outcome::Win, _ => panic!("elf choice not valid! {}",elf) } }, MY_PAPER => { match elf { ROCK => return Outcome::Win, PAPER => return Outcome::Draw, SCIS => return Outcome::Lose, _ => panic!("elf choice not valid! {}",elf) } }, MY_SCIS => { match elf { ROCK => return Outcome::Lose, PAPER => return Outcome::Win, SCIS => return Outcome::Draw, _ => panic!("elf choice not valid! {}",elf) } }, _ => panic!("My choice not valid {}", me) } } fn pick_move(elf: u8, outcome: u8) -> u8 { match outcome { WIN => match elf { ROCK => 2, //paper PAPER => 3, //scissors SCIS => 1, //rock _ => panic!("Unknown elf choice!"), }, LOSE => match elf { ROCK => 3, //scissors PAPER => 1, //rock SCIS => 2, //paper _ => panic!("Unknown elf choice!"), }, DRAW => match elf { ROCK => 1, //rock PAPER => 2, //paper SCIS => 3, //scissors _ => panic!("Unknown elf choice!"), }, _ => panic!("Unknown outcome") } } pub fn part1(v: &Vec<[u8;3]>) -> u32 { v.iter().map(|line| { let (outcome,score) = parse_line(line); match outcome { Outcome::Draw => score + 3, Outcome::Lose => score, Outcome::Win => score + 6 } }) .fold(0, |acc, x| acc + (x as u32)) } pub fn part2(v: &Vec<[u8;3]>) -> u32 { v.iter().map(|line| { let outcome_score = match line[2] { LOSE => 0, DRAW => 3, WIN => 6, _ => panic!("Unknown outcome!") }; let choice_score = pick_move(line[0],line[2]); outcome_score + choice_score }).fold(0, |acc, x| acc + (x as u32)) }
Методология фундаментальна — перебирать каждую строку, сопоставлять символы дважды.
Оно работает. Это не слишком медленно. Но это громоздко, и это одно из тех плохих решений, которые многословны, но и не очень понятны для него. В общем, я не в восторге от этого. Кто-то поделился со мной замечательным однострочником, который работает, признавая, что символы UTF-8 для каждого выбора разделены только числом 1 и упорядочены таким образом, чтобы баллы выровнялись… Я оставлю вас, чтобы выяснить отдых для среды без спойлеров.
Итак, мы здесь. Немного поспешил, потому что сегодня я тоже прошел первый день, но я определенно начинаю чувствовать себя намного более комфортно с управлением встроенной памятью.
Вперед на 3 день!