use std::io::Read; use nom::{ bytes::complete::tag, character::complete::{alpha1, digit1}, combinator::map_parser, multi::separated_list1, sequence::{preceded, terminated}, IResult, }; fn main() -> Result<(), anyhow::Error> { let mut input = String::new(); std::io::stdin().read_to_string(&mut input)?; let (rest, input) = parse_input(&input).unwrap(); assert!(rest.is_empty()); part1(&input); part2(&input); Ok(()) } fn solve(input: &Input) -> i64 { let b = (input.prize.y * input.buttons[0].x - input.prize.x * input.buttons[0].y) / (input.buttons[1].y * input.buttons[0].x - input.buttons[1].x * input.buttons[0].y); let a = (input.prize.x - b * input.buttons[1].x) / input.buttons[0].x; if input.buttons[0].x * a + input.buttons[1].x * b == input.prize.x && input.buttons[0].y * a + input.buttons[1].y * b == input.prize.y { 3 * a + b } else { 0 } } fn part1(input: &[Input]) { eprintln!("{}", input.iter().map(solve).sum::()); } fn part2(input: &[Input]) { eprintln!( "{}", input .iter() .cloned() .map(|v| Input { prize: Coords { x: v.prize.x + 10_000_000_000_000, y: v.prize.y + 10_000_000_000_000, }, ..v }) .map(|v| solve(&v)) .sum::() ); } #[derive(Debug, Copy, Clone)] pub struct Coords { x: i64, y: i64, } #[derive(Debug, Clone)] pub struct Input { buttons: Vec, prize: Coords, } fn parse_i64(s: &str) -> IResult<&str, i64> { map_parser(digit1, nom::character::complete::i64)(s) } fn parse_button(s: &str) -> IResult<&str, Coords> { let (s, _b) = preceded(tag("Button "), alpha1)(s)?; let (s, x) = preceded(tag(": X+"), parse_i64)(s)?; let (s, y) = preceded(tag(", Y+"), parse_i64)(s)?; Ok((s, Coords { x, y })) } fn parse_prize(s: &str) -> IResult<&str, Coords> { let (s, x) = preceded(tag("Prize: X="), parse_i64)(s)?; let (s, y) = preceded(tag(", Y="), parse_i64)(s)?; Ok((s, Coords { x, y })) } fn parse_block(s: &str) -> IResult<&str, Input> { let (s, buttons) = terminated(separated_list1(tag("\n"), parse_button), tag("\n"))(s)?; let (s, prize) = terminated(parse_prize, tag("\n"))(s)?; Ok((s, Input { buttons, prize })) } fn parse_input(s: &'_ str) -> IResult<&'_ str, Vec> { separated_list1(tag("\n"), parse_block)(s) }