mirror of
https://codeberg.org/JasterV/aoc_2021.git
synced 2026-04-26 18:40:05 +00:00
day4 first puzzle
This commit is contained in:
parent
f8f107f4ef
commit
bc24a5b37f
2 changed files with 128 additions and 9 deletions
|
|
@ -1,24 +1,45 @@
|
|||
mod models;
|
||||
|
||||
use itertools::{FoldWhile::*, Itertools};
|
||||
use models::{Board, Cell, COLUMNS, ROWS};
|
||||
use models::Board;
|
||||
use std::fs;
|
||||
use std::io::Result;
|
||||
|
||||
static INPUT_PATH: &str = "test.txt";
|
||||
static INPUT_PATH: &str = "input.txt";
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let (nums, boards) = read_game(INPUT_PATH)?;
|
||||
let (last_num, winning_board) = play_game(&nums, boards);
|
||||
let unmarked_cells_sum = winning_board
|
||||
.iter()
|
||||
.filter(|cell| !cell.is_marked())
|
||||
.map(|cell| cell.into_inner())
|
||||
.sum::<u16>();
|
||||
println!("First puzzle: {}", last_num * unmarked_cells_sum);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn read_game(filename: &str) -> Result<(Vec<u8>, Vec<Board>)> {
|
||||
fn read_game(filename: &str) -> Result<(Vec<u16>, Vec<Board>)> {
|
||||
let contents = fs::read_to_string(filename)?;
|
||||
let splits: Vec<&str> = contents.split("\n\n").collect();
|
||||
let nums_to_draw: Vec<u8> = splits[0]
|
||||
let nums_to_draw: Vec<u16> = splits[0]
|
||||
.split(',')
|
||||
.map(|num| num.parse().unwrap())
|
||||
.collect();
|
||||
let boards: Vec<Board> = splits[1..].iter().map(|&row| Board::from(row)).collect();
|
||||
Ok((nums_to_draw, boards))
|
||||
}
|
||||
|
||||
fn play_game(nums: &[u16], boards: Vec<Board>) -> (u16, Board) {
|
||||
let (last_num, boards) = nums
|
||||
.iter()
|
||||
.fold_while((0, boards), |(last_num, boards), &num| {
|
||||
if boards.iter().any(|board| board.has_won()) {
|
||||
return Done((last_num, boards));
|
||||
}
|
||||
Continue((num, boards.iter().map(|board| board.mark(num)).collect()))
|
||||
})
|
||||
.into_inner();
|
||||
let winning_board = boards.into_iter().find(|board| board.has_won()).unwrap();
|
||||
(last_num, winning_board)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
pub const COLUMNS: usize = 4;
|
||||
pub const COLUMNS: usize = 5;
|
||||
pub const ROWS: usize = 5;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum Cell {
|
||||
Marked(u8),
|
||||
UnMarked(u8),
|
||||
Marked(u16),
|
||||
UnMarked(u16),
|
||||
}
|
||||
|
||||
impl Cell {
|
||||
|
|
@ -14,6 +14,13 @@ impl Cell {
|
|||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_inner(&self) -> u16 {
|
||||
match self {
|
||||
Cell::Marked(num) => *num,
|
||||
Cell::UnMarked(num) => *num,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
@ -22,7 +29,7 @@ pub struct Board {
|
|||
}
|
||||
|
||||
impl Board {
|
||||
pub fn mark(&self, num: u8) -> Board {
|
||||
pub fn mark(&self, num: u16) -> Board {
|
||||
let cells = self
|
||||
.cells
|
||||
.iter()
|
||||
|
|
@ -58,6 +65,10 @@ impl Board {
|
|||
.map(|col| self.get(row, col))
|
||||
.all(|cell| cell.map_or(false, |cell| cell.is_marked()))
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> std::slice::Iter<'_, Cell> {
|
||||
self.cells.iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for Board {
|
||||
|
|
@ -70,3 +81,90 @@ impl From<&str> for Board {
|
|||
Board { cells }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{Board, Cell};
|
||||
|
||||
const BOARD_STR: &'static str = r#"
|
||||
14 21 17 24 4
|
||||
10 16 15 9 19
|
||||
18 8 23 26 20
|
||||
22 11 13 6 5
|
||||
2 0 12 3 7"#;
|
||||
|
||||
#[test]
|
||||
fn creates_board_from_str() {
|
||||
let nums: [u16; 25] = [
|
||||
14, 21, 17, 24, 4, 10, 16, 15, 9, 19, 18, 8, 23, 26, 20, 22, 11, 13, 6, 5, 2, 0, 12, 3,
|
||||
7,
|
||||
];
|
||||
let expected_cells: Vec<Cell> = nums.iter().copied().map(Cell::UnMarked).collect();
|
||||
let board = Board::from(BOARD_STR);
|
||||
assert_eq!(expected_cells, board.cells);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn marks_cell() {
|
||||
let num_to_mark = 14;
|
||||
let nums: [u16; 25] = [
|
||||
14, 21, 17, 24, 4, 10, 16, 15, 9, 19, 18, 8, 23, 26, 20, 22, 11, 13, 6, 5, 2, 0, 12, 3,
|
||||
7,
|
||||
];
|
||||
let board = Board::from(BOARD_STR).mark(num_to_mark);
|
||||
let marked_cells: Vec<Cell> = board
|
||||
.cells
|
||||
.into_iter()
|
||||
.filter(|cell| cell.is_marked())
|
||||
.collect();
|
||||
let expected_marked_cells: Vec<Cell> = nums
|
||||
.iter()
|
||||
.copied()
|
||||
.filter(|&num| num == num_to_mark)
|
||||
.map(Cell::Marked)
|
||||
.collect();
|
||||
assert_eq!(marked_cells, expected_marked_cells);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gets_cell_by_row_and_column() {
|
||||
let board = Board::from(BOARD_STR);
|
||||
let cell_0_0 = board.get(0, 0);
|
||||
let cell_5_5 = board.get(4, 4);
|
||||
let cell_2_3 = board.get(2, 3);
|
||||
assert_eq!(cell_0_0, Some(&Cell::UnMarked(14)));
|
||||
assert_eq!(cell_5_5, Some(&Cell::UnMarked(7)));
|
||||
assert_eq!(cell_2_3, Some(&Cell::UnMarked(26)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn checks_if_row_is_marked() {
|
||||
let first_row: [u16; 5] = [14, 21, 17, 24, 4];
|
||||
let board = Board::from(BOARD_STR);
|
||||
assert!(!board.has_won());
|
||||
let board = first_row.iter().fold(board, |board, &num| board.mark(num));
|
||||
assert!(board.has_won());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn checks_row_not_marked() {
|
||||
let almost_first_row: [u16; 4] = [14, 21, 17, 24];
|
||||
let board = Board::from(BOARD_STR);
|
||||
assert!(!board.has_won());
|
||||
let board = almost_first_row
|
||||
.iter()
|
||||
.fold(board, |board, &num| board.mark(num));
|
||||
assert!(!board.has_won());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn checks_marked_column() {
|
||||
let first_column: [u16; 5] = [14, 10, 18, 22, 2];
|
||||
let board = Board::from(BOARD_STR);
|
||||
assert!(!board.has_won());
|
||||
let board = first_column
|
||||
.iter()
|
||||
.fold(board, |board, &num| board.mark(num));
|
||||
assert!(board.has_won());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue