Compare commits
2 Commits
eb7467f615
...
b67ed69f7d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b67ed69f7d | ||
|
|
ad3b71b159 |
1
input/day13.txt
Normal file
1
input/day13.txt
Normal file
File diff suppressed because one or more lines are too long
@@ -1,5 +1,5 @@
|
||||
mod tasks;
|
||||
|
||||
fn main() {
|
||||
tasks::day12::run();
|
||||
tasks::day13::run();
|
||||
}
|
||||
|
||||
234
src/tasks/day13.rs
Normal file
234
src/tasks/day13.rs
Normal file
@@ -0,0 +1,234 @@
|
||||
use super::day05::{IntCodeComputer, RAM};
|
||||
use itertools::Itertools;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn run() {
|
||||
let program: RAM = std::fs::read_to_string("input/day13.txt")
|
||||
.unwrap()
|
||||
.split(",")
|
||||
.map(|it| it.parse::<i128>().unwrap())
|
||||
.enumerate()
|
||||
.collect();
|
||||
task1(program.clone());
|
||||
task2_ai(program.clone());
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
enum FieldType {
|
||||
Empty,
|
||||
Wall,
|
||||
Block,
|
||||
HorizontalPaddle,
|
||||
Ball,
|
||||
}
|
||||
|
||||
impl fmt::Display for FieldType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
match self {
|
||||
Self::Empty => " ",
|
||||
Self::Wall => "X",
|
||||
Self::Block => "B",
|
||||
Self::HorizontalPaddle => "_",
|
||||
Self::Ball => "O",
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl FieldType {
|
||||
fn from(input: i128) -> Self {
|
||||
match input {
|
||||
0 => Self::Empty,
|
||||
1 => Self::Wall,
|
||||
2 => Self::Block,
|
||||
3 => Self::HorizontalPaddle,
|
||||
4 => Self::Ball,
|
||||
_ => unreachable!("unexpected field type {}", input),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Game {
|
||||
pc: IntCodeComputer,
|
||||
field: HashMap<(i128, i128), FieldType>,
|
||||
score: i128,
|
||||
show_output: bool,
|
||||
}
|
||||
|
||||
impl Game {
|
||||
fn new(coins: Option<i128>, mut ram: RAM, show_output: bool) -> Self {
|
||||
if let Some(c) = coins {
|
||||
ram.insert(0, c);
|
||||
}
|
||||
let pc = IntCodeComputer::new(vec![], ram);
|
||||
Game {
|
||||
pc,
|
||||
field: HashMap::new(),
|
||||
score: 0,
|
||||
show_output,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* true means the game is over, false means input is awaited
|
||||
*/
|
||||
fn run(&mut self) -> bool {
|
||||
self.pc.clear_output();
|
||||
let done = self.pc.run_until_input_empty();
|
||||
let output = self.pc.get_output().into_iter().map(|it| *it).collect_vec();
|
||||
let mut score = 0;
|
||||
output
|
||||
.iter()
|
||||
.tuples()
|
||||
.scan(&mut self.field, |map, (x, y, t)| {
|
||||
if *x == -1 && *y == 0 {
|
||||
score = *t;
|
||||
} else {
|
||||
map.insert((*x, *y), FieldType::from(*t));
|
||||
}
|
||||
Some(())
|
||||
})
|
||||
.any(|_| false);
|
||||
self.score = score;
|
||||
if self.show_output {
|
||||
self.print();
|
||||
}
|
||||
done
|
||||
}
|
||||
|
||||
fn set_input(&mut self, input: Input) {
|
||||
self.pc.set_input(&[input.int()]);
|
||||
}
|
||||
|
||||
fn print(&self) {
|
||||
let xmin = *self.field.iter().map(|((x, _), _)| x).min().unwrap();
|
||||
let xmax = *self.field.iter().map(|((x, _), _)| x).max().unwrap();
|
||||
let ymin = *self.field.iter().map(|((_, y), _)| y).min().unwrap();
|
||||
let ymax = *self.field.iter().map(|((_, y), _)| y).max().unwrap();
|
||||
for y in ymin..=ymax {
|
||||
for x in xmin..=xmax {
|
||||
if let Some(f) = self.field.get(&(x, y)) {
|
||||
print!("{}", f);
|
||||
} else {
|
||||
panic!("There is an unspecified tile in the field");
|
||||
}
|
||||
}
|
||||
println!();
|
||||
}
|
||||
println!("Score: {}", self.score);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
enum Input {
|
||||
Neutral,
|
||||
Left,
|
||||
Right,
|
||||
}
|
||||
|
||||
impl Input {
|
||||
fn int(&self) -> i128 {
|
||||
match self {
|
||||
Self::Neutral => 0,
|
||||
Self::Left => -1,
|
||||
Self::Right => 1,
|
||||
}
|
||||
}
|
||||
|
||||
fn from(input: char) -> Self {
|
||||
match input {
|
||||
's' => Self::Neutral,
|
||||
'a' => Self::Left,
|
||||
'd' => Self::Right,
|
||||
_ => Self::Neutral,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn task1(program: RAM) {
|
||||
let mut game = Game::new(None, program, true);
|
||||
if game.run() {
|
||||
let block_count = game
|
||||
.field
|
||||
.iter()
|
||||
.filter(|(_, ftype)| **ftype == FieldType::Block)
|
||||
.count();
|
||||
println!("Task 1: There are {} blocks in the field", block_count);
|
||||
} else {
|
||||
unreachable!("In this task the game should end without any input.");
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn task2(program: RAM) {
|
||||
use std::io::{self, BufRead};
|
||||
let mut game = Game::new(Some(2), program, true);
|
||||
let stdin = io::stdin();
|
||||
let mut input_iter = stdin.lock().lines();
|
||||
while !game.run() {
|
||||
// read input
|
||||
let next = input_iter.next().unwrap().unwrap().chars().next();
|
||||
if let Some(s) = next {
|
||||
game.set_input(Input::from(s));
|
||||
} else {
|
||||
game.set_input(Input::Neutral);
|
||||
}
|
||||
}
|
||||
println!(
|
||||
"You won against the game! Your final score was {}",
|
||||
game.score
|
||||
);
|
||||
}
|
||||
|
||||
fn task2_ai(program: RAM) {
|
||||
let mut game = Game::new(Some(2), program, false);
|
||||
let mut moves = 0;
|
||||
while !game.run() {
|
||||
// always keep the paddle under the ball
|
||||
let x_ball = game
|
||||
.field
|
||||
.iter()
|
||||
.find_map(|((x, _), t)| {
|
||||
if *t == FieldType::Ball {
|
||||
Some(*x)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
let x_paddle = game
|
||||
.field
|
||||
.iter()
|
||||
.find_map(|((x, _), t)| {
|
||||
if *t == FieldType::HorizontalPaddle {
|
||||
Some(*x)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
let direction = if x_ball < x_paddle {
|
||||
Input::Left
|
||||
} else if x_ball > x_paddle {
|
||||
Input::Right
|
||||
} else {
|
||||
Input::Neutral
|
||||
};
|
||||
game.set_input(direction);
|
||||
moves += 1;
|
||||
}
|
||||
println!("Played for {} moves", moves);
|
||||
println!(
|
||||
"Game is over! There are {} blocks left. Your final score is {}",
|
||||
game.field
|
||||
.iter()
|
||||
.filter(|(_, t)| **t == FieldType::Block)
|
||||
.count(),
|
||||
game.score
|
||||
);
|
||||
}
|
||||
@@ -9,3 +9,4 @@ pub mod day09;
|
||||
pub mod day10;
|
||||
pub mod day11;
|
||||
pub mod day12;
|
||||
pub mod day13;
|
||||
|
||||
Reference in New Issue
Block a user