day15 part1 combat with errors
This commit is contained in:
@@ -1,9 +1,7 @@
|
||||
#########
|
||||
#G..G..G#
|
||||
#.......#
|
||||
#.......#
|
||||
#G..E..G#
|
||||
#.......#
|
||||
#.......#
|
||||
#G..G..G#
|
||||
#########
|
||||
#######
|
||||
#.G...#
|
||||
#...EG#
|
||||
#.#.#G#
|
||||
#..G#E#
|
||||
#.....#
|
||||
#######
|
||||
@@ -4,28 +4,34 @@ use std::collections::HashSet;
|
||||
use std::collections::VecDeque;
|
||||
use std::fmt::Display;
|
||||
|
||||
const ATTACK_POWER: i32 = 3;
|
||||
const HEALTH: i32 = 200;
|
||||
|
||||
pub fn task1() {
|
||||
let input = utils::read_file("input/day15.txt");
|
||||
let mut game = Game::from_input(input.lines().collect());
|
||||
println!("{}", game);
|
||||
game.round();
|
||||
println!("{}", game);
|
||||
game.round();
|
||||
println!("{}", game);
|
||||
game.round();
|
||||
println!("{}", game);
|
||||
game.round();
|
||||
println!("{}", game);
|
||||
let mut round = 0;
|
||||
while game.round() {
|
||||
round += 1;
|
||||
println!("{}", game);
|
||||
println!("{:?}", game.units);
|
||||
}
|
||||
println!("Final full round was {}", round);
|
||||
println!(
|
||||
"Remaining HP: {}",
|
||||
game.units.iter().map(|it| it.health).sum::<i32>()
|
||||
);
|
||||
println!("{:?}", game.units);
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
enum Tile {
|
||||
Empty,
|
||||
Wall,
|
||||
Unit(WarriorType),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||
enum WarriorType {
|
||||
Elve,
|
||||
Goblin,
|
||||
@@ -79,6 +85,7 @@ impl Ord for Position {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Warrior {
|
||||
warrior_type: WarriorType,
|
||||
position: Position,
|
||||
@@ -129,7 +136,6 @@ impl Game {
|
||||
.filter_map(|(delta, start)| {
|
||||
let map = Map::from_game(&self, *start);
|
||||
if let Some(path) = map.shortest_path(*start, to) {
|
||||
//println!("Path from {:?}: {:?}", start, path);
|
||||
Some((delta + path.len() * 10, *path.first().unwrap_or(start)))
|
||||
} else {
|
||||
None
|
||||
@@ -143,10 +149,23 @@ impl Game {
|
||||
}
|
||||
}
|
||||
|
||||
fn round(&mut self) {
|
||||
/// Returns true if a full round was played, false if the round aborted because all
|
||||
/// enemies of one party are dead
|
||||
fn round(&mut self) -> bool {
|
||||
self.units.sort_unstable_by_key(|it| it.position);
|
||||
|
||||
for curr in 0..self.units.len() {
|
||||
let mut curr = 0;
|
||||
while curr < self.units.len() {
|
||||
if !self
|
||||
.units
|
||||
.iter()
|
||||
.any(|warrior| warrior.warrior_type == self.units[curr].warrior_type.enemy_type())
|
||||
{
|
||||
println!("There are no enemies anymore!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// movement phase
|
||||
if let Some(next_target_position) = self.closest_fighting_position(
|
||||
self.units[curr].position,
|
||||
self.units[curr].warrior_type.enemy_type(),
|
||||
@@ -154,20 +173,46 @@ impl Game {
|
||||
if let Some(next_position) =
|
||||
self.next_position(self.units[curr].position, next_target_position)
|
||||
{
|
||||
// println!(
|
||||
// "{:?} -> {:?} ({:?})",
|
||||
// self.units[curr].position, next_target_position, next_position
|
||||
// );
|
||||
let curr_pos = self.units[curr].position;
|
||||
self.tiles[curr_pos.0][curr_pos.1] = Tile::Empty;
|
||||
self.units[curr].position = next_position;
|
||||
self.tiles[next_position.0][next_position.1] =
|
||||
Tile::Unit(self.units[curr].warrior_type);
|
||||
} else {
|
||||
panic!("We have a reachable target but no path to it!");
|
||||
}
|
||||
}
|
||||
|
||||
// attack phase
|
||||
let neighbors = self.units[curr].position.neighbors(self.width, self.height);
|
||||
let mut close_enemies: Vec<usize> = self
|
||||
.units
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(_, it)| neighbors.contains(&it.position))
|
||||
.map(|(i, _)| i)
|
||||
.collect();
|
||||
close_enemies.sort_unstable_by(|a, b| {
|
||||
let a = &self.units[*a];
|
||||
let b = &self.units[*b];
|
||||
if a.health == b.health {
|
||||
a.position.cmp(&b.position)
|
||||
} else {
|
||||
a.health.cmp(&b.health)
|
||||
}
|
||||
});
|
||||
if let Some(closest_index) = close_enemies.first() {
|
||||
let enemy = &mut self.units[*closest_index];
|
||||
enemy.health -= ATTACK_POWER;
|
||||
if enemy.health <= 0 {
|
||||
let enemy = self.units.remove(*closest_index);
|
||||
if *closest_index < curr {
|
||||
curr -= 1;
|
||||
}
|
||||
self.tiles[enemy.position.0][enemy.position.1] = Tile::Empty;
|
||||
}
|
||||
}
|
||||
curr += 1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
fn from_input(input: Vec<&str>) -> Self {
|
||||
@@ -190,17 +235,17 @@ impl Game {
|
||||
units.push(Warrior {
|
||||
warrior_type: Elve,
|
||||
position: Position(x, y),
|
||||
health: 300,
|
||||
health: HEALTH,
|
||||
});
|
||||
Unit(Elve)
|
||||
Empty
|
||||
}
|
||||
'G' => {
|
||||
units.push(Warrior {
|
||||
warrior_type: Goblin,
|
||||
position: Position(x, y),
|
||||
health: 300,
|
||||
health: HEALTH,
|
||||
});
|
||||
Unit(Goblin)
|
||||
Empty
|
||||
}
|
||||
c => panic!("Unexpected input character '{}'", c),
|
||||
}
|
||||
@@ -231,8 +276,6 @@ impl Display for Game {
|
||||
line.push(match &self.tiles[x][y] {
|
||||
Empty => '.',
|
||||
Wall => '#',
|
||||
Unit(WarriorType::Elve) => 'E',
|
||||
Unit(WarriorType::Goblin) => 'G',
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -335,7 +378,6 @@ impl Map {
|
||||
}
|
||||
|
||||
fn find_closest_target(&self, from: Position) -> Option<Position> {
|
||||
// println!("{}", self);
|
||||
let mut open: VecDeque<(usize, Position)> = VecDeque::new();
|
||||
open.push_back((0, from));
|
||||
let mut visited: HashSet<Position> = HashSet::new();
|
||||
|
||||
Reference in New Issue
Block a user