Compare commits
2 Commits
3f2ff6e5a2
...
ba622fd408
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ba622fd408 | ||
|
|
cef96d55be |
@@ -1,4 +1,4 @@
|
|||||||
fn main() {
|
fn main() {
|
||||||
aoc_2018::tasks::day15::task1();
|
// aoc_2018::tasks::day15::task1();
|
||||||
// aoc_2018::tasks::day15::task2();
|
aoc_2018::tasks::day15::task2();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,16 +4,17 @@ use std::collections::HashSet;
|
|||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
|
||||||
const ATTACK_POWER: i32 = 3;
|
|
||||||
const HEALTH: i32 = 200;
|
const HEALTH: i32 = 200;
|
||||||
|
|
||||||
pub fn task1() {
|
pub fn task1() {
|
||||||
let input = utils::read_file("input/day15.txt");
|
let input = utils::read_file("input/day15.txt");
|
||||||
let mut game = Game::from_input(input.lines().collect());
|
let mut game = Game::from_input(&input.lines().collect(), 3, 3);
|
||||||
println!("{}", game);
|
println!("{}", game);
|
||||||
let mut round = 0;
|
let mut round = 0;
|
||||||
while game.round() {
|
while game.round() {
|
||||||
round += 1;
|
round += 1;
|
||||||
|
// println!("{}", game);
|
||||||
|
// println!("round was {}", round);
|
||||||
}
|
}
|
||||||
println!("Final full round was {}", round);
|
println!("Final full round was {}", round);
|
||||||
println!(
|
println!(
|
||||||
@@ -22,6 +23,45 @@ pub fn task1() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn task2() {
|
||||||
|
let input = utils::read_file("input/day15.txt");
|
||||||
|
let input = input.lines().collect();
|
||||||
|
let mut highest_fail = 3;
|
||||||
|
let mut lowest_win = None::<i32>;
|
||||||
|
while lowest_win.is_none() || lowest_win.unwrap() - 1 > highest_fail {
|
||||||
|
let attack = match lowest_win {
|
||||||
|
Some(upper) => highest_fail + (upper - highest_fail) / 2,
|
||||||
|
None => 2 * highest_fail,
|
||||||
|
};
|
||||||
|
let mut game = Game::from_input(&input, 3, attack);
|
||||||
|
let initial_elve_count = game
|
||||||
|
.units
|
||||||
|
.iter()
|
||||||
|
.filter(|unit| unit.warrior_type == WarriorType::Elve)
|
||||||
|
.count();
|
||||||
|
let mut round = 0;
|
||||||
|
while game.round() {
|
||||||
|
round += 1;
|
||||||
|
}
|
||||||
|
if game
|
||||||
|
.units
|
||||||
|
.iter()
|
||||||
|
.filter(|unit| unit.warrior_type == WarriorType::Elve)
|
||||||
|
.count()
|
||||||
|
== initial_elve_count
|
||||||
|
{
|
||||||
|
lowest_win = Some(attack);
|
||||||
|
} else {
|
||||||
|
highest_fail = attack;
|
||||||
|
}
|
||||||
|
println!(
|
||||||
|
"Result: {}",
|
||||||
|
game.units.iter().map(|it| it.health).sum::<i32>() * round as i32
|
||||||
|
);
|
||||||
|
}
|
||||||
|
println!("Searching stopped with lowest win {:?}", lowest_win); // 7169 too low
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq)]
|
#[derive(Clone, PartialEq)]
|
||||||
enum Tile {
|
enum Tile {
|
||||||
Empty,
|
Empty,
|
||||||
@@ -101,6 +141,7 @@ struct Warrior {
|
|||||||
warrior_type: WarriorType,
|
warrior_type: WarriorType,
|
||||||
position: Position,
|
position: Position,
|
||||||
health: i32,
|
health: i32,
|
||||||
|
attack: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Game {
|
struct Game {
|
||||||
@@ -136,25 +177,32 @@ impl Game {
|
|||||||
if from == to {
|
if from == to {
|
||||||
return Some(from);
|
return Some(from);
|
||||||
}
|
}
|
||||||
let input = vec![
|
// let input = vec![
|
||||||
(1, Position(from.0, from.1 - 1)),
|
// (1, Position(from.0, from.1 - 1)),
|
||||||
(2, Position(from.0 - 1, from.1)),
|
// (2, Position(from.0 - 1, from.1)),
|
||||||
(3, Position(from.0 + 1, from.1)),
|
// (3, Position(from.0 + 1, from.1)),
|
||||||
(4, Position(from.0, from.1 + 1)),
|
// (4, Position(from.0, from.1 + 1)),
|
||||||
];
|
// ];
|
||||||
if let Some((_, best)) = input
|
// if let Some((_, best)) = input
|
||||||
.iter()
|
// .iter()
|
||||||
.filter_map(|(delta, start)| {
|
// .filter_map(|(delta, start)| {
|
||||||
let map = Map::from_game(&self, from);
|
// let map = Map::from_game(&self, from);
|
||||||
if let Some(path) = map.shortest_path(*start, to) {
|
// if let Some(path) = map.shortest_path(*start, to) {
|
||||||
Some((delta + path.len() * 10, *path.first().unwrap_or(start)))
|
// Some((delta + path.len() * 10, *path.first().unwrap_or(start)))
|
||||||
} else {
|
// } else {
|
||||||
None
|
// None
|
||||||
}
|
// }
|
||||||
})
|
// })
|
||||||
.min_by_key(|(d, _)| *d)
|
// .min_by_key(|(d, _)| *d)
|
||||||
{
|
// {
|
||||||
Some(best)
|
// Some(best)
|
||||||
|
// } else {
|
||||||
|
// None
|
||||||
|
// }
|
||||||
|
let map = Map::from_game(&self, from);
|
||||||
|
if let Some(path) = map.shortest_path(from, to) {
|
||||||
|
// println!("{:?}", path);
|
||||||
|
Some(*path.get(1).unwrap_or(&from))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@@ -185,6 +233,10 @@ impl Game {
|
|||||||
if let Some(next_position) =
|
if let Some(next_position) =
|
||||||
self.next_position(self.units[curr].position, next_target_position)
|
self.next_position(self.units[curr].position, next_target_position)
|
||||||
{
|
{
|
||||||
|
// println!(
|
||||||
|
// "{:?} moves to {:?} via {:?}",
|
||||||
|
// self.units[curr].position, next_target_position, next_position
|
||||||
|
// );
|
||||||
self.units[curr].position = next_position;
|
self.units[curr].position = next_position;
|
||||||
} else {
|
} else {
|
||||||
panic!("We have a reachable target but no path to it! {:?} wants to go to {:?}", self.units[curr], next_target_position);
|
panic!("We have a reachable target but no path to it! {:?} wants to go to {:?}", self.units[curr], next_target_position);
|
||||||
@@ -219,8 +271,9 @@ impl Game {
|
|||||||
{
|
{
|
||||||
panic!("Distance WTF")
|
panic!("Distance WTF")
|
||||||
}
|
}
|
||||||
|
let attack = self.units[curr].attack;
|
||||||
let enemy = &mut self.units[*closest_index];
|
let enemy = &mut self.units[*closest_index];
|
||||||
enemy.health -= ATTACK_POWER;
|
enemy.health -= attack;
|
||||||
if enemy.health <= 0 {
|
if enemy.health <= 0 {
|
||||||
let enemy = self.units.remove(*closest_index);
|
let enemy = self.units.remove(*closest_index);
|
||||||
if *closest_index < curr {
|
if *closest_index < curr {
|
||||||
@@ -234,7 +287,7 @@ impl Game {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_input(input: Vec<&str>) -> Self {
|
fn from_input(input: &Vec<&str>, goblin_attack: i32, elve_attack: i32) -> Self {
|
||||||
use self::Tile::*;
|
use self::Tile::*;
|
||||||
use self::WarriorType::*;
|
use self::WarriorType::*;
|
||||||
let width = input[0].len();
|
let width = input[0].len();
|
||||||
@@ -255,6 +308,7 @@ impl Game {
|
|||||||
warrior_type: Elve,
|
warrior_type: Elve,
|
||||||
position: Position(x, y),
|
position: Position(x, y),
|
||||||
health: HEALTH,
|
health: HEALTH,
|
||||||
|
attack: elve_attack,
|
||||||
});
|
});
|
||||||
Empty
|
Empty
|
||||||
}
|
}
|
||||||
@@ -263,6 +317,7 @@ impl Game {
|
|||||||
warrior_type: Goblin,
|
warrior_type: Goblin,
|
||||||
position: Position(x, y),
|
position: Position(x, y),
|
||||||
health: HEALTH,
|
health: HEALTH,
|
||||||
|
attack: goblin_attack,
|
||||||
});
|
});
|
||||||
Empty
|
Empty
|
||||||
}
|
}
|
||||||
@@ -391,6 +446,7 @@ impl Map {
|
|||||||
if let Some(Some(_)) = predecessors.get(&to) {
|
if let Some(Some(_)) = predecessors.get(&to) {
|
||||||
let mut result: Vec<Position> = Vec::new();
|
let mut result: Vec<Position> = Vec::new();
|
||||||
let mut current = to;
|
let mut current = to;
|
||||||
|
result.push(current);
|
||||||
while let Some(Some(predecessor)) = predecessors.get(¤t) {
|
while let Some(Some(predecessor)) = predecessors.get(¤t) {
|
||||||
result.push(*predecessor);
|
result.push(*predecessor);
|
||||||
current = *predecessor;
|
current = *predecessor;
|
||||||
|
|||||||
Reference in New Issue
Block a user