use std::io; use std::env; use std::fs::File; use std::io::BufReader; use std::io::BufRead; use std::fmt::Debug; #[derive(Debug)] struct Shape { bot: [i8; 4], // distance from datum. -1 for unused. top: [i8; 4], left: [i8; 4], right: [i8; 4], width: usize, height: usize, } // a Shape's datum is its bottom left corner #[derive(Debug)] struct Pos {y: usize, x: usize} //static SHAPE_NAMES: [char; 5] = ['-', '+', 'L', '|', '.']; static SHAPES: [Shape; 5] = [ Shape { // - bot: [0, 0, 0, 0], top: [0, 0, 0, 0], left: [0, -1, -1, -1], right: [3, -1, -1, -1], width: 4, height: 1, }, Shape { // + bot: [1, 0, 1, -1], top: [1, 2, 1, -1], left: [1, 0, 1, -1], right: [1, 2, 1, -1], width: 3, height: 3, }, Shape { // backward L bot: [0, 0, 0, -1], top: [0, 0, 2, -1], left: [0, 2, 2, -1], right: [2, 2, 2, -1], width: 3, height: 3, }, Shape { // | bot: [0, -1, -1, -1], top: [0, -1, -1, -1], left: [0, 0, 0, 0], right: [0, 0, 0, 0], width: 1, height: 4, }, Shape { // square bot: [0, 0, -1, -1], top: [1, 1, -1, -1], left: [0, 0, -1, -1], right: [1, 1, -1, -1], width: 2, height: 2, }, ]; fn iterate( map: &mut Vec<[u8; 7]>, shape: &Shape, pos: &mut Pos, wind: u8 ) -> bool { //println!(" __ {}, start {:?}", wind as char, pos); // Wind move match wind { b'>' => 'rightmove: { if pos.x + shape.width == 7 { break 'rightmove; } let mut i = 0; while i < 4 && shape.right[i] >= 0 { let right_point = pos.x + shape.right[i] as usize; if right_point + 1 == 7 { break 'rightmove; } if map[pos.y + i][right_point + 1] != 0 { break 'rightmove; } i += 1; } pos.x += 1; //println!(" >> {:?}", pos); }, b'<' => 'leftmove: { if pos.x == 0 { break 'leftmove; } let mut i = 0; while i < 4 && shape.left[i] >= 0 { let left_point = pos.x + shape.left[i] as usize; if left_point == 0 { break 'leftmove; } if map[pos.y + i][left_point - 1] != 0 { break 'leftmove; } i += 1; } pos.x -= 1; //println!(" << {:?}", pos); }, _ => panic!(), } // Gravity move 'downmove: { let mut i = 0; while i < 4 && shape.bot[i] >= 0 { let bot_point = pos.y + shape.bot[i] as usize; if bot_point == 0 { break 'downmove; } if map[bot_point - 1][pos.x + i] != 0 { break 'downmove; } i += 1; } pos.y -= 1; //println!(" vv {:?}", pos); return false; } // Settling let mut i = 0; while i < 4 && shape.left[i] >= 0 && shape.right[i] >= 0 { map[pos.y + i][pos.x + shape.left[i] as usize] = 1; map[pos.y + i][pos.x + shape.right[i] as usize] = 1; i += 1; } i = 0; while i < 4 && shape.top[i] >= 0 && shape.bot[i] >= 0 { map[pos.y + shape.top[i] as usize][pos.x + i] = 1; map[pos.y + shape.bot[i] as usize][pos.x + i] = 1; i += 1; } return true; } fn main() -> io::Result<()> { let input_fname = env::args().nth(1).expect("need input file"); let limit = env::args().nth(2).expect("need limit").parse::().unwrap(); let mut winds: Vec = Vec::new(); let _ = BufReader::new(File::open(input_fname)?).read_until(b'\n', &mut winds); if winds.last() == Some(&b'\n') { winds.pop(); } println!("winds = {}, shapes = {}", winds.len(), SHAPES.len()); let mut shape_id = 0; let mut shape = &SHAPES[shape_id]; let mut current_top = 0; let mut shape_pos = Pos{x: 2, y: 3}; let mut map: Vec<[u8; 7]> = vec![ [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], ]; let mut answers: Vec<(usize, usize)> = Vec::new(); let mut i = 0; 'mainloop: while answers.len() < limit { let c = winds[i % winds.len()]; if iterate(&mut map, shape, &mut shape_pos, c) { let last_shape_top = shape_pos.y + shape.height - 1; if last_shape_top > current_top { current_top = last_shape_top; } shape_id = (shape_id + 1) % SHAPES.len(); // next shape shape = &SHAPES[shape_id]; for _ in map.len()..(current_top + 4 + shape.height) { map.push([0, 0, 0, 0, 0, 0, 0]); } shape_pos = Pos{x:2, y: current_top + 4}; answers.push((i, current_top)); let last_rock = answers.len() - 1; print!( "rock {} - (i {}, top {})", last_rock, i, current_top ); if last_rock >= 2*SHAPES.len() { let mut j = last_rock - SHAPES.len(); 'lookback: while j > (last_rock / 2) { let (hist_i, hist_top) = answers[j]; let next_j = 2*j - last_rock; let (hist2_i, hist2_top) = answers[next_j]; if (i - hist_i) % winds.len() == 0 && (i - hist_i) == (hist_i - hist2_i) && (current_top - hist_top) == (hist_top - hist2_top) { print!( " {}-{}-{}-({}-{}-{})", j, hist_i, hist_top, next_j, hist2_i, hist2_top, ); print!( " rock cycle {}, off {} | \ top cycle {} off {} ", last_rock - j, next_j, current_top - hist_top, hist2_top, ); if (limit - 1 - next_j) % (last_rock - j) == 0 { let n_cycles = (limit - 1 - next_j) / (last_rock - j); println!( "\nheight = {}", hist2_top + n_cycles*(current_top - hist_top) + 1 ); break 'mainloop; } else { break 'lookback; } } j -= SHAPES.len(); } } println!(); //prettyprint(&map, &shape_pos, SHAPE_NAMES[shape_id]); } i += 1; } Ok(()) } fn prettyprint(map: &Vec<[u8; 7]>, pos: &Pos, shape_name: char) { let mut i = map.len(); for row in map.into_iter().rev() { i -= 1; print!("|"); for j in 0..7 { print!("{}", if row[j] == 0 { "." } else { "#" }); } println!("| {} {}", i, if i == pos.y {shape_name} else {' '}); } }