Compare commits

...

2 Commits

Author SHA1 Message Date
Johannes
b67ed69f7d day 13 task 2 2019-12-14 18:02:24 +01:00
Johannes
ad3b71b159 day 13 task 1 2019-12-14 16:53:42 +01:00
4 changed files with 237 additions and 1 deletions

1
input/day13.txt Normal file

File diff suppressed because one or more lines are too long

View File

@@ -1,5 +1,5 @@
mod tasks; mod tasks;
fn main() { fn main() {
tasks::day12::run(); tasks::day13::run();
} }

234
src/tasks/day13.rs Normal file
View 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
);
}

View File

@@ -9,3 +9,4 @@ pub mod day09;
pub mod day10; pub mod day10;
pub mod day11; pub mod day11;
pub mod day12; pub mod day12;
pub mod day13;