192 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			192 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| use std::collections::{HashSet};
 | |
| 
 | |
| #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
 | |
| struct Pos (i32, i32); 
 | |
| 
 | |
| const WIDTH :i32 = 7; 
 | |
| const FLOOR :i32 = -1; 
 | |
| 
 | |
| 
 | |
| fn find_highest(map :&HashSet<Pos>) -> i32 {
 | |
| 
 | |
|     let mut max = -1;
 | |
| 
 | |
|     for pos in map {
 | |
|         if pos.1 > max {
 | |
|             max = pos.1; 
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     max
 | |
| }
 | |
| 
 | |
| fn evaluate_stream(mut pos :Pos, stream :char) -> Pos {
 | |
|     match stream {
 | |
|         '>' => { pos.0 += 1 }
 | |
|         '<' => { pos.0 -= 1 }
 | |
|         _ => { }
 | |
|     }
 | |
| 
 | |
|     pos
 | |
| }
 | |
| 
 | |
| fn evaluate_rock_movement(positions :&mut HashSet<Pos>, current_rock_pos :&Vec<Pos>, stream_index :&mut usize, stream :&String) {
 | |
| 
 | |
|     let mut moving_rock_pos = current_rock_pos.clone(); 
 | |
| 
 | |
|     loop {
 | |
| 
 | |
|         // get current stream 
 | |
|         let current_stream = stream.chars().nth(*stream_index).unwrap();
 | |
|         *stream_index = (*stream_index + 1) % stream.len(); 
 | |
| 
 | |
|         // move according to stream
 | |
|         let future_pos = moving_rock_pos.iter().map(|elem| evaluate_stream(*elem, current_stream)).collect::<Vec<Pos>>(); 
 | |
| 
 | |
|         // check for collisions 
 | |
|         let mut collision = false; 
 | |
|         for pos in &future_pos {
 | |
|             if pos.0 < 0 || pos.0 >= WIDTH || pos.1 < 0 || positions.contains(&pos) {
 | |
|                 collision = true; 
 | |
|                 break; 
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // move rock if no collision took place
 | |
|         if !collision {
 | |
|             moving_rock_pos = future_pos; 
 | |
|         }
 | |
| 
 | |
| 
 | |
|         // move down 
 | |
|         let future_pos = moving_rock_pos.iter().map(|elem| Pos(elem.0, elem.1 - 1)).collect::<Vec<Pos>>(); 
 | |
|         
 | |
|         // check for collisions 
 | |
|         let mut collision = false; 
 | |
|         for pos in &future_pos {
 | |
|             if pos.0 < 0 || pos.0 >= WIDTH || pos.1 < 0 || positions.contains(&pos) {
 | |
|                 collision = true; 
 | |
|                 break; 
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // move rock if no collision took place
 | |
|         // if a collision took place then add every old position of the rock to the map and return 
 | |
|         if !collision {
 | |
|             moving_rock_pos = future_pos; 
 | |
|         } else {
 | |
| 
 | |
|             for pos in moving_rock_pos {
 | |
|                 positions.insert(pos); 
 | |
|             }
 | |
| 
 | |
|             return; 
 | |
| 
 | |
|         }
 | |
| 
 | |
| 
 | |
|     }
 | |
|     
 | |
| }
 | |
| 
 | |
| fn print_board(positions :&HashSet<Pos>) {
 | |
| 
 | |
|     let height = find_highest(positions); 
 | |
| 
 | |
|     if height == -1 {
 | |
|         return; 
 | |
|     }
 | |
| 
 | |
| 
 | |
|     let mut map :Vec<Vec<char>> = vec![vec!['.'; WIDTH as usize]; height as usize + 1]; 
 | |
| 
 | |
|     for pos in positions {
 | |
|         map[pos.1 as usize][pos.0 as usize] = '#'; 
 | |
|     }
 | |
| 
 | |
|     for v in (0..map.len()).rev() {
 | |
|         for c in &map[v] {
 | |
|             print!("{}", c); 
 | |
|         }
 | |
|         println!(); 
 | |
|     }
 | |
| 
 | |
| }
 | |
| 
 | |
| pub fn run(inp :Vec<String>) {
 | |
|     
 | |
|     let stream = &inp[0]; 
 | |
| 
 | |
|     const NUM_ROCKS :i64 = 1000000000000; 
 | |
| 
 | |
|     const HEIGHT_OFFSET :i32 = 3; 
 | |
|     
 | |
|     let shape_offset :Vec<(Vec<Pos>, i32)> = vec![
 | |
|         (vec![Pos(-1, 0), Pos(0, 0), Pos(1, 0), Pos(2, 0)], 1), // Minus
 | |
|         (vec![Pos(0, 0), Pos(0, 1), Pos(1, 1), Pos(-1, 1), Pos(0, 2)], 3), // Plus
 | |
|         (vec![Pos(1, 0), Pos(1, 1), Pos(1, 2), Pos(0, 2), Pos(-1, 2)], 3), // Reverse L
 | |
|         (vec![Pos(-1, 0), Pos(-1, 1), Pos(-1, 2), Pos(-1, 3)], 4), // Line (Vertical) 
 | |
|         (vec![Pos(-1, 0), Pos(0, 0), Pos(0, 1), Pos(-1, 1)], 2), // Square
 | |
|         ]; 
 | |
|         
 | |
|     let mut positions :HashSet<Pos> = HashSet::new();  
 | |
|     
 | |
|     let mut default_spawn = Pos(3, HEIGHT_OFFSET); 
 | |
| 
 | |
|     let mut stream_index = 0; 
 | |
|     let mut shape_index = 0; 
 | |
| 
 | |
|     // store the height each time a row is completely full and reset the map 
 | |
|     let mut current_height = 0; 
 | |
| 
 | |
|     for rock_num in 0..NUM_ROCKS {
 | |
|         
 | |
| 
 | |
|         let mut highest_point = find_highest(&positions); 
 | |
| 
 | |
|         // check if the top row is completely filled 
 | |
|         // if so we know that we can reset the board
 | |
|         let mut can_be_reset = true; 
 | |
|         for i in 0..WIDTH {
 | |
|             if !positions.contains(&Pos(i, highest_point)) {
 | |
|                 can_be_reset = false; 
 | |
|                 break; 
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         if can_be_reset {
 | |
|             println!("Reset: stream:{}, block:{}", stream_index, shape_index); 
 | |
|             println!("i:{}", rock_num); 
 | |
|             println!("h:{}", highest_point); 
 | |
| 
 | |
|             current_height += highest_point + 1; 
 | |
|             positions.clear(); 
 | |
|             highest_point = -1;
 | |
|         }
 | |
| 
 | |
|         // get new rock offset 
 | |
|         let mut new_rock = shape_offset[shape_index].clone(); 
 | |
|         
 | |
|         // update spawn position
 | |
|         default_spawn.1 = highest_point + HEIGHT_OFFSET + new_rock.1; 
 | |
|         
 | |
|         // calculate new rock Position  
 | |
|         for offset in &mut new_rock.0 {
 | |
|             offset.0 = default_spawn.0 + offset.0;
 | |
|             offset.1 = default_spawn.1 - offset.1;
 | |
|         }
 | |
| 
 | |
|         // evaluate current rock fall
 | |
|         evaluate_rock_movement(&mut positions, &new_rock.0, &mut stream_index, stream); 
 | |
| 
 | |
|         // go to next rock 
 | |
|         shape_index = (shape_index + 1) % shape_offset.len();  
 | |
| 
 | |
|     }
 | |
| 
 | |
|     //print_board(&positions); 
 | |
| 
 | |
|     let height = find_highest(&positions); 
 | |
|     println!("a2: {}", current_height + height + 1); 
 | |
| 
 | |
| } |